Skip to main content

logicaffeine_kernel/
prelude.rs

1//! Standard Library for the Kernel.
2//!
3//! Defines fundamental types and logical connectives:
4//! - Entity: domain of individuals (for FOL)
5//! - Nat: natural numbers
6//! - True, False: propositional constants
7//! - Eq: propositional equality
8//! - And, Or: logical connectives
9
10use crate::context::Context;
11use crate::term::{Term, Universe};
12
13/// Standard library definitions.
14pub struct StandardLibrary;
15
16impl StandardLibrary {
17    /// Register all standard library definitions in the context.
18    pub fn register(ctx: &mut Context) {
19        Self::register_entity(ctx);
20        Self::register_nat(ctx);
21        Self::register_bool(ctx);
22        Self::register_tlist(ctx);
23        Self::register_true(ctx);
24        Self::register_false(ctx);
25        Self::register_not(ctx);
26        Self::register_eq(ctx);
27        Self::register_and(ctx);
28        Self::register_or(ctx);
29        Self::register_ex(ctx);
30        Self::register_primitives(ctx);
31        Self::register_reflection(ctx);
32        Self::register_hardware(ctx);
33    }
34
35    /// Primitive types and operations.
36    ///
37    /// Int : Type 0 (64-bit signed integer)
38    /// Float : Type 0 (64-bit floating point)
39    /// Text : Type 0 (UTF-8 string)
40    /// Duration : Type 0 (nanoseconds, i64 - physical time)
41    /// Date : Type 0 (days since epoch, i32 - calendar date)
42    /// Moment : Type 0 (nanoseconds since epoch, i64 - instant in UTC)
43    ///
44    /// add, sub, mul, div, mod : Int -> Int -> Int
45    fn register_primitives(ctx: &mut Context) {
46        // Opaque types (no constructors, cannot be pattern-matched)
47        ctx.add_inductive("Int", Term::Sort(Universe::Type(0)));
48        ctx.add_inductive("Float", Term::Sort(Universe::Type(0)));
49        ctx.add_inductive("Text", Term::Sort(Universe::Type(0)));
50
51        // Temporal types (opaque, no constructors)
52        ctx.add_inductive("Duration", Term::Sort(Universe::Type(0)));
53        ctx.add_inductive("Date", Term::Sort(Universe::Type(0)));
54        ctx.add_inductive("Moment", Term::Sort(Universe::Type(0)));
55
56        let int = Term::Global("Int".to_string());
57
58        // Binary Int -> Int -> Int type
59        let bin_int_type = Term::Pi {
60            param: "_".to_string(),
61            param_type: Box::new(int.clone()),
62            body_type: Box::new(Term::Pi {
63                param: "_".to_string(),
64                param_type: Box::new(int.clone()),
65                body_type: Box::new(int.clone()),
66            }),
67        };
68
69        // Register arithmetic builtins as declarations (axioms with computational behavior)
70        ctx.add_declaration("add", bin_int_type.clone());
71        ctx.add_declaration("sub", bin_int_type.clone());
72        ctx.add_declaration("mul", bin_int_type.clone());
73        ctx.add_declaration("div", bin_int_type.clone());
74        ctx.add_declaration("mod", bin_int_type);
75
76        // Temporal operations
77        let duration = Term::Global("Duration".to_string());
78        let date = Term::Global("Date".to_string());
79        let moment = Term::Global("Moment".to_string());
80        let bool_type = Term::Global("Bool".to_string());
81
82        // Duration -> Duration -> Duration
83        let bin_duration_type = Term::Pi {
84            param: "_".to_string(),
85            param_type: Box::new(duration.clone()),
86            body_type: Box::new(Term::Pi {
87                param: "_".to_string(),
88                param_type: Box::new(duration.clone()),
89                body_type: Box::new(duration.clone()),
90            }),
91        };
92
93        // Duration -> Int -> Duration
94        let duration_int_duration_type = Term::Pi {
95            param: "_".to_string(),
96            param_type: Box::new(duration.clone()),
97            body_type: Box::new(Term::Pi {
98                param: "_".to_string(),
99                param_type: Box::new(int.clone()),
100                body_type: Box::new(duration.clone()),
101            }),
102        };
103
104        // Duration arithmetic: add, sub, mul, div
105        ctx.add_declaration("add_duration", bin_duration_type.clone());
106        ctx.add_declaration("sub_duration", bin_duration_type.clone());
107        ctx.add_declaration("mul_duration", duration_int_duration_type.clone());
108        ctx.add_declaration("div_duration", duration_int_duration_type);
109
110        // Date -> Int -> Date (add days offset)
111        let date_int_date_type = Term::Pi {
112            param: "_".to_string(),
113            param_type: Box::new(date.clone()),
114            body_type: Box::new(Term::Pi {
115                param: "_".to_string(),
116                param_type: Box::new(int.clone()),
117                body_type: Box::new(date.clone()),
118            }),
119        };
120        ctx.add_declaration("date_add_days", date_int_date_type);
121
122        // Date -> Date -> Int (difference in days)
123        let date_date_int_type = Term::Pi {
124            param: "_".to_string(),
125            param_type: Box::new(date.clone()),
126            body_type: Box::new(Term::Pi {
127                param: "_".to_string(),
128                param_type: Box::new(date.clone()),
129                body_type: Box::new(int.clone()),
130            }),
131        };
132        ctx.add_declaration("date_sub_date", date_date_int_type);
133
134        // Moment -> Duration -> Moment
135        let moment_duration_moment_type = Term::Pi {
136            param: "_".to_string(),
137            param_type: Box::new(moment.clone()),
138            body_type: Box::new(Term::Pi {
139                param: "_".to_string(),
140                param_type: Box::new(duration.clone()),
141                body_type: Box::new(moment.clone()),
142            }),
143        };
144        ctx.add_declaration("moment_add_duration", moment_duration_moment_type);
145
146        // Moment -> Moment -> Duration
147        let moment_moment_duration_type = Term::Pi {
148            param: "_".to_string(),
149            param_type: Box::new(moment.clone()),
150            body_type: Box::new(Term::Pi {
151                param: "_".to_string(),
152                param_type: Box::new(moment.clone()),
153                body_type: Box::new(duration.clone()),
154            }),
155        };
156        ctx.add_declaration("moment_sub_moment", moment_moment_duration_type);
157
158        // Comparison operations: X -> X -> Bool
159        let date_date_bool_type = Term::Pi {
160            param: "_".to_string(),
161            param_type: Box::new(date.clone()),
162            body_type: Box::new(Term::Pi {
163                param: "_".to_string(),
164                param_type: Box::new(date),
165                body_type: Box::new(bool_type.clone()),
166            }),
167        };
168        ctx.add_declaration("date_lt", date_date_bool_type);
169
170        let moment_moment_bool_type = Term::Pi {
171            param: "_".to_string(),
172            param_type: Box::new(moment.clone()),
173            body_type: Box::new(Term::Pi {
174                param: "_".to_string(),
175                param_type: Box::new(moment),
176                body_type: Box::new(bool_type.clone()),
177            }),
178        };
179        ctx.add_declaration("moment_lt", moment_moment_bool_type);
180
181        let duration_duration_bool_type = Term::Pi {
182            param: "_".to_string(),
183            param_type: Box::new(duration.clone()),
184            body_type: Box::new(Term::Pi {
185                param: "_".to_string(),
186                param_type: Box::new(duration),
187                body_type: Box::new(bool_type),
188            }),
189        };
190        ctx.add_declaration("duration_lt", duration_duration_bool_type);
191    }
192
193    /// Entity : Type 0
194    ///
195    /// The domain of individuals for first-order logic.
196    /// Proper names like "Socrates" are declared as Entity.
197    /// Predicates like "Man" are declared as Entity → Prop.
198    fn register_entity(ctx: &mut Context) {
199        ctx.add_inductive("Entity", Term::Sort(Universe::Type(0)));
200    }
201
202    /// Nat : Type 0
203    /// Zero : Nat
204    /// Succ : Nat → Nat
205    fn register_nat(ctx: &mut Context) {
206        let nat = Term::Global("Nat".to_string());
207
208        // Nat : Type 0
209        ctx.add_inductive("Nat", Term::Sort(Universe::Type(0)));
210
211        // Zero : Nat
212        ctx.add_constructor("Zero", "Nat", nat.clone());
213
214        // Succ : Nat → Nat
215        ctx.add_constructor(
216            "Succ",
217            "Nat",
218            Term::Pi {
219                param: "_".to_string(),
220                param_type: Box::new(nat.clone()),
221                body_type: Box::new(nat),
222            },
223        );
224    }
225
226    /// Bool : Type 0
227    /// true : Bool
228    /// false : Bool
229    fn register_bool(ctx: &mut Context) {
230        let bool_type = Term::Global("Bool".to_string());
231
232        // Bool : Type 0
233        ctx.add_inductive("Bool", Term::Sort(Universe::Type(0)));
234
235        // true : Bool
236        ctx.add_constructor("true", "Bool", bool_type.clone());
237
238        // false : Bool
239        ctx.add_constructor("false", "Bool", bool_type);
240    }
241
242    /// TList : Type 0 -> Type 0
243    /// TNil : Π(A : Type 0). TList A
244    /// TCons : Π(A : Type 0). A -> TList A -> TList A
245    fn register_tlist(ctx: &mut Context) {
246        let type0 = Term::Sort(Universe::Type(0));
247        let a = Term::Var("A".to_string());
248
249        // TList : Type 0 -> Type 0
250        let tlist_type = Term::Pi {
251            param: "A".to_string(),
252            param_type: Box::new(type0.clone()),
253            body_type: Box::new(type0.clone()),
254        };
255        ctx.add_inductive("TList", tlist_type);
256
257        // TList A
258        let tlist_a = Term::App(
259            Box::new(Term::Global("TList".to_string())),
260            Box::new(a.clone()),
261        );
262
263        // TNil : Π(A : Type 0). TList A
264        let tnil_type = Term::Pi {
265            param: "A".to_string(),
266            param_type: Box::new(type0.clone()),
267            body_type: Box::new(tlist_a.clone()),
268        };
269        ctx.add_constructor("TNil", "TList", tnil_type);
270
271        // TCons : Π(A : Type 0). A -> TList A -> TList A
272        let tcons_type = Term::Pi {
273            param: "A".to_string(),
274            param_type: Box::new(type0),
275            body_type: Box::new(Term::Pi {
276                param: "_".to_string(),
277                param_type: Box::new(a.clone()),
278                body_type: Box::new(Term::Pi {
279                    param: "_".to_string(),
280                    param_type: Box::new(tlist_a.clone()),
281                    body_type: Box::new(tlist_a),
282                }),
283            }),
284        };
285        ctx.add_constructor("TCons", "TList", tcons_type);
286
287        // Convenience aliases for tactic lists (Syntax -> Derivation)
288        Self::register_tactic_list_helpers(ctx);
289    }
290
291    /// TTactics : Type 0 = TList (Syntax -> Derivation)
292    /// TacNil : TTactics
293    /// TacCons : (Syntax -> Derivation) -> TTactics -> TTactics
294    ///
295    /// Convenience wrappers to avoid explicit type arguments for tactic lists.
296    fn register_tactic_list_helpers(ctx: &mut Context) {
297        let syntax = Term::Global("Syntax".to_string());
298        let derivation = Term::Global("Derivation".to_string());
299
300        // Tactic type: Syntax -> Derivation
301        let tactic_type = Term::Pi {
302            param: "_".to_string(),
303            param_type: Box::new(syntax.clone()),
304            body_type: Box::new(derivation.clone()),
305        };
306
307        // TTactics = TList (Syntax -> Derivation)
308        let ttactics = Term::App(
309            Box::new(Term::Global("TList".to_string())),
310            Box::new(tactic_type.clone()),
311        );
312
313        // TTactics : Type 0
314        ctx.add_definition("TTactics".to_string(), Term::Sort(Universe::Type(0)), ttactics.clone());
315
316        // TacNil : TTactics = TNil (Syntax -> Derivation)
317        let tac_nil_body = Term::App(
318            Box::new(Term::Global("TNil".to_string())),
319            Box::new(tactic_type.clone()),
320        );
321        ctx.add_definition("TacNil".to_string(), ttactics.clone(), tac_nil_body);
322
323        // TacCons : (Syntax -> Derivation) -> TTactics -> TTactics
324        let tac_cons_type = Term::Pi {
325            param: "t".to_string(),
326            param_type: Box::new(tactic_type.clone()),
327            body_type: Box::new(Term::Pi {
328                param: "ts".to_string(),
329                param_type: Box::new(ttactics.clone()),
330                body_type: Box::new(ttactics.clone()),
331            }),
332        };
333
334        // TacCons t ts = TCons (Syntax -> Derivation) t ts
335        let tac_cons_body = Term::Lambda {
336            param: "t".to_string(),
337            param_type: Box::new(tactic_type.clone()),
338            body: Box::new(Term::Lambda {
339                param: "ts".to_string(),
340                param_type: Box::new(ttactics.clone()),
341                body: Box::new(Term::App(
342                    Box::new(Term::App(
343                        Box::new(Term::App(
344                            Box::new(Term::Global("TCons".to_string())),
345                            Box::new(tactic_type),
346                        )),
347                        Box::new(Term::Var("t".to_string())),
348                    )),
349                    Box::new(Term::Var("ts".to_string())),
350                )),
351            }),
352        };
353        ctx.add_definition("TacCons".to_string(), tac_cons_type, tac_cons_body);
354    }
355
356    /// True : Prop
357    /// I : True
358    fn register_true(ctx: &mut Context) {
359        ctx.add_inductive("True", Term::Sort(Universe::Prop));
360        ctx.add_constructor("I", "True", Term::Global("True".to_string()));
361    }
362
363    /// False : Prop
364    /// (no constructors)
365    fn register_false(ctx: &mut Context) {
366        ctx.add_inductive("False", Term::Sort(Universe::Prop));
367    }
368
369    /// Not : Prop -> Prop
370    /// Not P := P -> False
371    fn register_not(ctx: &mut Context) {
372        // Type: Π(P : Prop). Prop
373        let not_type = Term::Pi {
374            param: "P".to_string(),
375            param_type: Box::new(Term::Sort(Universe::Prop)),
376            body_type: Box::new(Term::Sort(Universe::Prop)),
377        };
378
379        // Body: λ(P : Prop). Π(_ : P). False
380        let not_body = Term::Lambda {
381            param: "P".to_string(),
382            param_type: Box::new(Term::Sort(Universe::Prop)),
383            body: Box::new(Term::Pi {
384                param: "_".to_string(),
385                param_type: Box::new(Term::Var("P".to_string())),
386                body_type: Box::new(Term::Global("False".to_string())),
387            }),
388        };
389
390        ctx.add_definition("Not".to_string(), not_type, not_body);
391    }
392
393    /// Eq : Π(A : Type 0). A → A → Prop
394    /// refl : Π(A : Type 0). Π(x : A). Eq A x x
395    fn register_eq(ctx: &mut Context) {
396        // Eq : Π(A : Type 0). A → A → Prop
397        let eq_type = Term::Pi {
398            param: "A".to_string(),
399            param_type: Box::new(Term::Sort(Universe::Type(0))),
400            body_type: Box::new(Term::Pi {
401                param: "x".to_string(),
402                param_type: Box::new(Term::Var("A".to_string())),
403                body_type: Box::new(Term::Pi {
404                    param: "y".to_string(),
405                    param_type: Box::new(Term::Var("A".to_string())),
406                    body_type: Box::new(Term::Sort(Universe::Prop)),
407                }),
408            }),
409        };
410        ctx.add_inductive("Eq", eq_type);
411
412        // refl : Π(A : Type 0). Π(x : A). Eq A x x
413        let refl_type = Term::Pi {
414            param: "A".to_string(),
415            param_type: Box::new(Term::Sort(Universe::Type(0))),
416            body_type: Box::new(Term::Pi {
417                param: "x".to_string(),
418                param_type: Box::new(Term::Var("A".to_string())),
419                body_type: Box::new(Term::App(
420                    Box::new(Term::App(
421                        Box::new(Term::App(
422                            Box::new(Term::Global("Eq".to_string())),
423                            Box::new(Term::Var("A".to_string())),
424                        )),
425                        Box::new(Term::Var("x".to_string())),
426                    )),
427                    Box::new(Term::Var("x".to_string())),
428                )),
429            }),
430        };
431        ctx.add_constructor("refl", "Eq", refl_type);
432
433        // Eq_rec : Π(A:Type). Π(x:A). Π(P:A→Prop). P x → Π(y:A). Eq A x y → P y
434        // The eliminator for equality - Leibniz's Law
435        Self::register_eq_rec(ctx);
436
437        // Eq_sym : Π(A:Type). Π(x:A). Π(y:A). Eq A x y → Eq A y x
438        Self::register_eq_sym(ctx);
439
440        // Eq_trans : Π(A:Type). Π(x:A). Π(y:A). Π(z:A). Eq A x y → Eq A y z → Eq A x z
441        Self::register_eq_trans(ctx);
442    }
443
444    /// Eq_rec : Π(A:Type). Π(x:A). Π(P:A→Prop). P x → Π(y:A). Eq A x y → P y
445    /// The eliminator for equality - Leibniz's Law / Substitution of Equals
446    fn register_eq_rec(ctx: &mut Context) {
447        let a = Term::Var("A".to_string());
448        let x = Term::Var("x".to_string());
449        let y = Term::Var("y".to_string());
450        let p = Term::Var("P".to_string());
451
452        // P x = P applied to x
453        let p_x = Term::App(Box::new(p.clone()), Box::new(x.clone()));
454
455        // P y = P applied to y
456        let p_y = Term::App(Box::new(p.clone()), Box::new(y.clone()));
457
458        // Eq A x y
459        let eq_a_x_y = Term::App(
460            Box::new(Term::App(
461                Box::new(Term::App(
462                    Box::new(Term::Global("Eq".to_string())),
463                    Box::new(a.clone()),
464                )),
465                Box::new(x.clone()),
466            )),
467            Box::new(y.clone()),
468        );
469
470        // P : A → Prop
471        let p_type = Term::Pi {
472            param: "_".to_string(),
473            param_type: Box::new(a.clone()),
474            body_type: Box::new(Term::Sort(Universe::Prop)),
475        };
476
477        // Full type: Π(A:Type). Π(x:A). Π(P:A→Prop). P x → Π(y:A). Eq A x y → P y
478        let eq_rec_type = Term::Pi {
479            param: "A".to_string(),
480            param_type: Box::new(Term::Sort(Universe::Type(0))),
481            body_type: Box::new(Term::Pi {
482                param: "x".to_string(),
483                param_type: Box::new(a.clone()),
484                body_type: Box::new(Term::Pi {
485                    param: "P".to_string(),
486                    param_type: Box::new(p_type),
487                    body_type: Box::new(Term::Pi {
488                        param: "_".to_string(),
489                        param_type: Box::new(p_x),
490                        body_type: Box::new(Term::Pi {
491                            param: "y".to_string(),
492                            param_type: Box::new(a),
493                            body_type: Box::new(Term::Pi {
494                                param: "_".to_string(),
495                                param_type: Box::new(eq_a_x_y),
496                                body_type: Box::new(p_y),
497                            }),
498                        }),
499                    }),
500                }),
501            }),
502        };
503
504        ctx.add_declaration("Eq_rec", eq_rec_type);
505    }
506
507    /// Eq_sym : Π(A:Type). Π(x:A). Π(y:A). Eq A x y → Eq A y x
508    /// Symmetry of equality
509    fn register_eq_sym(ctx: &mut Context) {
510        let a = Term::Var("A".to_string());
511        let x = Term::Var("x".to_string());
512        let y = Term::Var("y".to_string());
513
514        // Eq A x y
515        let eq_a_x_y = Term::App(
516            Box::new(Term::App(
517                Box::new(Term::App(
518                    Box::new(Term::Global("Eq".to_string())),
519                    Box::new(a.clone()),
520                )),
521                Box::new(x.clone()),
522            )),
523            Box::new(y.clone()),
524        );
525
526        // Eq A y x
527        let eq_a_y_x = Term::App(
528            Box::new(Term::App(
529                Box::new(Term::App(
530                    Box::new(Term::Global("Eq".to_string())),
531                    Box::new(a.clone()),
532                )),
533                Box::new(y.clone()),
534            )),
535            Box::new(x.clone()),
536        );
537
538        // Π(A:Type). Π(x:A). Π(y:A). Eq A x y → Eq A y x
539        let eq_sym_type = Term::Pi {
540            param: "A".to_string(),
541            param_type: Box::new(Term::Sort(Universe::Type(0))),
542            body_type: Box::new(Term::Pi {
543                param: "x".to_string(),
544                param_type: Box::new(a.clone()),
545                body_type: Box::new(Term::Pi {
546                    param: "y".to_string(),
547                    param_type: Box::new(a),
548                    body_type: Box::new(Term::Pi {
549                        param: "_".to_string(),
550                        param_type: Box::new(eq_a_x_y),
551                        body_type: Box::new(eq_a_y_x),
552                    }),
553                }),
554            }),
555        };
556
557        ctx.add_declaration("Eq_sym", eq_sym_type);
558    }
559
560    /// Eq_trans : Π(A:Type). Π(x:A). Π(y:A). Π(z:A). Eq A x y → Eq A y z → Eq A x z
561    /// Transitivity of equality
562    fn register_eq_trans(ctx: &mut Context) {
563        let a = Term::Var("A".to_string());
564        let x = Term::Var("x".to_string());
565        let y = Term::Var("y".to_string());
566        let z = Term::Var("z".to_string());
567
568        // Eq A x y
569        let eq_a_x_y = Term::App(
570            Box::new(Term::App(
571                Box::new(Term::App(
572                    Box::new(Term::Global("Eq".to_string())),
573                    Box::new(a.clone()),
574                )),
575                Box::new(x.clone()),
576            )),
577            Box::new(y.clone()),
578        );
579
580        // Eq A y z
581        let eq_a_y_z = Term::App(
582            Box::new(Term::App(
583                Box::new(Term::App(
584                    Box::new(Term::Global("Eq".to_string())),
585                    Box::new(a.clone()),
586                )),
587                Box::new(y.clone()),
588            )),
589            Box::new(z.clone()),
590        );
591
592        // Eq A x z
593        let eq_a_x_z = Term::App(
594            Box::new(Term::App(
595                Box::new(Term::App(
596                    Box::new(Term::Global("Eq".to_string())),
597                    Box::new(a.clone()),
598                )),
599                Box::new(x.clone()),
600            )),
601            Box::new(z.clone()),
602        );
603
604        // Π(A:Type). Π(x:A). Π(y:A). Π(z:A). Eq A x y → Eq A y z → Eq A x z
605        let eq_trans_type = Term::Pi {
606            param: "A".to_string(),
607            param_type: Box::new(Term::Sort(Universe::Type(0))),
608            body_type: Box::new(Term::Pi {
609                param: "x".to_string(),
610                param_type: Box::new(a.clone()),
611                body_type: Box::new(Term::Pi {
612                    param: "y".to_string(),
613                    param_type: Box::new(a.clone()),
614                    body_type: Box::new(Term::Pi {
615                        param: "z".to_string(),
616                        param_type: Box::new(a),
617                        body_type: Box::new(Term::Pi {
618                            param: "_".to_string(),
619                            param_type: Box::new(eq_a_x_y),
620                            body_type: Box::new(Term::Pi {
621                                param: "_".to_string(),
622                                param_type: Box::new(eq_a_y_z),
623                                body_type: Box::new(eq_a_x_z),
624                            }),
625                        }),
626                    }),
627                }),
628            }),
629        };
630
631        ctx.add_declaration("Eq_trans", eq_trans_type);
632    }
633
634    /// And : Prop → Prop → Prop
635    /// conj : Π(P : Prop). Π(Q : Prop). P → Q → And P Q
636    fn register_and(ctx: &mut Context) {
637        // And : Prop → Prop → Prop
638        let and_type = Term::Pi {
639            param: "P".to_string(),
640            param_type: Box::new(Term::Sort(Universe::Prop)),
641            body_type: Box::new(Term::Pi {
642                param: "Q".to_string(),
643                param_type: Box::new(Term::Sort(Universe::Prop)),
644                body_type: Box::new(Term::Sort(Universe::Prop)),
645            }),
646        };
647        ctx.add_inductive("And", and_type);
648
649        // conj : Π(P : Prop). Π(Q : Prop). P → Q → And P Q
650        let conj_type = Term::Pi {
651            param: "P".to_string(),
652            param_type: Box::new(Term::Sort(Universe::Prop)),
653            body_type: Box::new(Term::Pi {
654                param: "Q".to_string(),
655                param_type: Box::new(Term::Sort(Universe::Prop)),
656                body_type: Box::new(Term::Pi {
657                    param: "p".to_string(),
658                    param_type: Box::new(Term::Var("P".to_string())),
659                    body_type: Box::new(Term::Pi {
660                        param: "q".to_string(),
661                        param_type: Box::new(Term::Var("Q".to_string())),
662                        body_type: Box::new(Term::App(
663                            Box::new(Term::App(
664                                Box::new(Term::Global("And".to_string())),
665                                Box::new(Term::Var("P".to_string())),
666                            )),
667                            Box::new(Term::Var("Q".to_string())),
668                        )),
669                    }),
670                }),
671            }),
672        };
673        ctx.add_constructor("conj", "And", conj_type);
674    }
675
676    /// Or : Prop → Prop → Prop
677    /// left : Π(P : Prop). Π(Q : Prop). P → Or P Q
678    /// right : Π(P : Prop). Π(Q : Prop). Q → Or P Q
679    fn register_or(ctx: &mut Context) {
680        // Or : Prop → Prop → Prop
681        let or_type = Term::Pi {
682            param: "P".to_string(),
683            param_type: Box::new(Term::Sort(Universe::Prop)),
684            body_type: Box::new(Term::Pi {
685                param: "Q".to_string(),
686                param_type: Box::new(Term::Sort(Universe::Prop)),
687                body_type: Box::new(Term::Sort(Universe::Prop)),
688            }),
689        };
690        ctx.add_inductive("Or", or_type);
691
692        // left : Π(P : Prop). Π(Q : Prop). P → Or P Q
693        let left_type = Term::Pi {
694            param: "P".to_string(),
695            param_type: Box::new(Term::Sort(Universe::Prop)),
696            body_type: Box::new(Term::Pi {
697                param: "Q".to_string(),
698                param_type: Box::new(Term::Sort(Universe::Prop)),
699                body_type: Box::new(Term::Pi {
700                    param: "p".to_string(),
701                    param_type: Box::new(Term::Var("P".to_string())),
702                    body_type: Box::new(Term::App(
703                        Box::new(Term::App(
704                            Box::new(Term::Global("Or".to_string())),
705                            Box::new(Term::Var("P".to_string())),
706                        )),
707                        Box::new(Term::Var("Q".to_string())),
708                    )),
709                }),
710            }),
711        };
712        ctx.add_constructor("left", "Or", left_type);
713
714        // right : Π(P : Prop). Π(Q : Prop). Q → Or P Q
715        let right_type = Term::Pi {
716            param: "P".to_string(),
717            param_type: Box::new(Term::Sort(Universe::Prop)),
718            body_type: Box::new(Term::Pi {
719                param: "Q".to_string(),
720                param_type: Box::new(Term::Sort(Universe::Prop)),
721                body_type: Box::new(Term::Pi {
722                    param: "q".to_string(),
723                    param_type: Box::new(Term::Var("Q".to_string())),
724                    body_type: Box::new(Term::App(
725                        Box::new(Term::App(
726                            Box::new(Term::Global("Or".to_string())),
727                            Box::new(Term::Var("P".to_string())),
728                        )),
729                        Box::new(Term::Var("Q".to_string())),
730                    )),
731                }),
732            }),
733        };
734        ctx.add_constructor("right", "Or", right_type);
735    }
736
737    /// Ex : Π(A : Type 0). (A → Prop) → Prop
738    /// witness : Π(A : Type 0). Π(P : A → Prop). Π(x : A). P x → Ex A P
739    ///
740    /// Ex is the existential type for propositions.
741    /// Ex A P means "there exists an x:A such that P(x)"
742    fn register_ex(ctx: &mut Context) {
743        // Ex : Π(A : Type 0). (A → Prop) → Prop
744        let ex_type = Term::Pi {
745            param: "A".to_string(),
746            param_type: Box::new(Term::Sort(Universe::Type(0))),
747            body_type: Box::new(Term::Pi {
748                param: "P".to_string(),
749                param_type: Box::new(Term::Pi {
750                    param: "_".to_string(),
751                    param_type: Box::new(Term::Var("A".to_string())),
752                    body_type: Box::new(Term::Sort(Universe::Prop)),
753                }),
754                body_type: Box::new(Term::Sort(Universe::Prop)),
755            }),
756        };
757        ctx.add_inductive("Ex", ex_type);
758
759        // witness : Π(A : Type 0). Π(P : A → Prop). Π(x : A). P x → Ex A P
760        //
761        // To construct an existential proof, provide:
762        // - A: the type being quantified over
763        // - P: the predicate
764        // - x: the witness (an element of A)
765        // - proof: evidence that P(x) holds
766        let a = Term::Var("A".to_string());
767        let p = Term::Var("P".to_string());
768        let x = Term::Var("x".to_string());
769
770        // P x = P applied to x
771        let p_x = Term::App(Box::new(p.clone()), Box::new(x.clone()));
772
773        // Ex A P = Ex applied to A, then to P
774        let ex_a_p = Term::App(
775            Box::new(Term::App(
776                Box::new(Term::Global("Ex".to_string())),
777                Box::new(a.clone()),
778            )),
779            Box::new(p.clone()),
780        );
781
782        let witness_type = Term::Pi {
783            param: "A".to_string(),
784            param_type: Box::new(Term::Sort(Universe::Type(0))),
785            body_type: Box::new(Term::Pi {
786                param: "P".to_string(),
787                param_type: Box::new(Term::Pi {
788                    param: "_".to_string(),
789                    param_type: Box::new(a.clone()),
790                    body_type: Box::new(Term::Sort(Universe::Prop)),
791                }),
792                body_type: Box::new(Term::Pi {
793                    param: "x".to_string(),
794                    param_type: Box::new(a),
795                    body_type: Box::new(Term::Pi {
796                        param: "_".to_string(),
797                        param_type: Box::new(p_x),
798                        body_type: Box::new(ex_a_p),
799                    }),
800                }),
801            }),
802        };
803        ctx.add_constructor("witness", "Ex", witness_type);
804    }
805
806    // -------------------------------------------------------------------------
807    // Reflection System (Deep Embedding)
808    // -------------------------------------------------------------------------
809
810    /// Reflection types for deep embedding.
811    ///
812    /// Univ : Type 0 (representation of universes)
813    /// Syntax : Type 0 (representation of terms with De Bruijn indices)
814    /// syn_size : Syntax -> Int (compute size of syntax tree)
815    /// syn_max_var : Syntax -> Int (compute max free variable index)
816    fn register_reflection(ctx: &mut Context) {
817        Self::register_univ(ctx);
818        Self::register_syntax(ctx);
819        Self::register_syn_size(ctx);
820        Self::register_syn_max_var(ctx);
821        Self::register_syn_lift(ctx);
822        Self::register_syn_subst(ctx);
823        Self::register_syn_beta(ctx);
824        Self::register_syn_step(ctx);
825        Self::register_syn_eval(ctx);
826        Self::register_syn_quote(ctx);
827        Self::register_syn_diag(ctx);
828        Self::register_derivation(ctx);
829        Self::register_concludes(ctx);
830        Self::register_try_refl(ctx);
831        Self::register_try_compute(ctx);
832        Self::register_try_cong(ctx);
833        Self::register_tact_fail(ctx);
834        Self::register_tact_orelse(ctx);
835        Self::register_tact_try(ctx);
836        Self::register_tact_repeat(ctx);
837        Self::register_tact_then(ctx);
838        Self::register_tact_first(ctx);
839        Self::register_tact_solve(ctx);
840        Self::register_try_ring(ctx);
841        Self::register_try_lia(ctx);
842        Self::register_try_cc(ctx);
843        Self::register_try_simp(ctx);
844        Self::register_try_omega(ctx);
845        Self::register_try_auto(ctx);
846        Self::register_try_induction(ctx);
847        Self::register_induction_helpers(ctx);
848        Self::register_try_inversion_tactic(ctx);
849        Self::register_operator_tactics(ctx);
850        Self::register_hw_tactics(ctx);
851    }
852
853    /// Univ : Type 0 (representation of universes)
854    /// UProp : Univ
855    /// UType : Int -> Univ
856    fn register_univ(ctx: &mut Context) {
857        let univ = Term::Global("Univ".to_string());
858        let int = Term::Global("Int".to_string());
859
860        // Univ : Type 0
861        ctx.add_inductive("Univ", Term::Sort(Universe::Type(0)));
862
863        // UProp : Univ
864        ctx.add_constructor("UProp", "Univ", univ.clone());
865
866        // UType : Int -> Univ
867        ctx.add_constructor(
868            "UType",
869            "Univ",
870            Term::Pi {
871                param: "_".to_string(),
872                param_type: Box::new(int),
873                body_type: Box::new(univ),
874            },
875        );
876    }
877
878    /// Syntax : Type 0 (representation of terms with De Bruijn indices)
879    ///
880    /// SVar : Int -> Syntax (De Bruijn variable index)
881    /// SGlobal : Int -> Syntax (global reference by ID)
882    /// SSort : Univ -> Syntax (universe)
883    /// SApp : Syntax -> Syntax -> Syntax (application)
884    /// SLam : Syntax -> Syntax -> Syntax (lambda: param_type, body)
885    /// SPi : Syntax -> Syntax -> Syntax (pi: param_type, body_type)
886    fn register_syntax(ctx: &mut Context) {
887        let syntax = Term::Global("Syntax".to_string());
888        let int = Term::Global("Int".to_string());
889        let univ = Term::Global("Univ".to_string());
890
891        // Syntax : Type 0
892        ctx.add_inductive("Syntax", Term::Sort(Universe::Type(0)));
893
894        // SVar : Int -> Syntax (De Bruijn index)
895        ctx.add_constructor(
896            "SVar",
897            "Syntax",
898            Term::Pi {
899                param: "_".to_string(),
900                param_type: Box::new(int.clone()),
901                body_type: Box::new(syntax.clone()),
902            },
903        );
904
905        // SGlobal : Int -> Syntax (global reference by ID)
906        ctx.add_constructor(
907            "SGlobal",
908            "Syntax",
909            Term::Pi {
910                param: "_".to_string(),
911                param_type: Box::new(int.clone()),
912                body_type: Box::new(syntax.clone()),
913            },
914        );
915
916        // SSort : Univ -> Syntax
917        ctx.add_constructor(
918            "SSort",
919            "Syntax",
920            Term::Pi {
921                param: "_".to_string(),
922                param_type: Box::new(univ),
923                body_type: Box::new(syntax.clone()),
924            },
925        );
926
927        // SApp : Syntax -> Syntax -> Syntax
928        ctx.add_constructor(
929            "SApp",
930            "Syntax",
931            Term::Pi {
932                param: "_".to_string(),
933                param_type: Box::new(syntax.clone()),
934                body_type: Box::new(Term::Pi {
935                    param: "_".to_string(),
936                    param_type: Box::new(syntax.clone()),
937                    body_type: Box::new(syntax.clone()),
938                }),
939            },
940        );
941
942        // SLam : Syntax -> Syntax -> Syntax (param_type, body)
943        ctx.add_constructor(
944            "SLam",
945            "Syntax",
946            Term::Pi {
947                param: "_".to_string(),
948                param_type: Box::new(syntax.clone()),
949                body_type: Box::new(Term::Pi {
950                    param: "_".to_string(),
951                    param_type: Box::new(syntax.clone()),
952                    body_type: Box::new(syntax.clone()),
953                }),
954            },
955        );
956
957        // SPi : Syntax -> Syntax -> Syntax (param_type, body_type)
958        ctx.add_constructor(
959            "SPi",
960            "Syntax",
961            Term::Pi {
962                param: "_".to_string(),
963                param_type: Box::new(syntax.clone()),
964                body_type: Box::new(Term::Pi {
965                    param: "_".to_string(),
966                    param_type: Box::new(syntax.clone()),
967                    body_type: Box::new(syntax.clone()),
968                }),
969            },
970        );
971
972        // SLit : Int -> Syntax (integer literal in quoted syntax)
973        ctx.add_constructor(
974            "SLit",
975            "Syntax",
976            Term::Pi {
977                param: "_".to_string(),
978                param_type: Box::new(int),
979                body_type: Box::new(syntax.clone()),
980            },
981        );
982
983        // SName : Text -> Syntax (named global reference)
984        let text = Term::Global("Text".to_string());
985        ctx.add_constructor(
986            "SName",
987            "Syntax",
988            Term::Pi {
989                param: "_".to_string(),
990                param_type: Box::new(text),
991                body_type: Box::new(syntax),
992            },
993        );
994    }
995
996    /// syn_size : Syntax -> Int
997    ///
998    /// Computes the number of nodes in a syntax tree.
999    /// Computational behavior defined in reduction.rs.
1000    fn register_syn_size(ctx: &mut Context) {
1001        let syntax = Term::Global("Syntax".to_string());
1002        let int = Term::Global("Int".to_string());
1003
1004        // syn_size : Syntax -> Int
1005        let syn_size_type = Term::Pi {
1006            param: "_".to_string(),
1007            param_type: Box::new(syntax),
1008            body_type: Box::new(int),
1009        };
1010
1011        ctx.add_declaration("syn_size", syn_size_type);
1012    }
1013
1014    /// syn_max_var : Syntax -> Int
1015    ///
1016    /// Returns the maximum free variable index in a syntax term.
1017    /// Returns -1 if the term is closed (all variables bound).
1018    /// Computational behavior defined in reduction.rs.
1019    fn register_syn_max_var(ctx: &mut Context) {
1020        let syntax = Term::Global("Syntax".to_string());
1021        let int = Term::Global("Int".to_string());
1022
1023        let syn_max_var_type = Term::Pi {
1024            param: "_".to_string(),
1025            param_type: Box::new(syntax),
1026            body_type: Box::new(int),
1027        };
1028
1029        ctx.add_declaration("syn_max_var", syn_max_var_type);
1030    }
1031
1032    // -------------------------------------------------------------------------
1033    // De Bruijn Operations (Substitution)
1034    // -------------------------------------------------------------------------
1035
1036    /// syn_lift : Int -> Int -> Syntax -> Syntax
1037    ///
1038    /// Shifts free variables (index >= cutoff) by amount.
1039    /// - syn_lift amount cutoff term
1040    /// - Variables with index < cutoff are bound -> unchanged
1041    /// - Variables with index >= cutoff are free -> add amount
1042    /// Computational behavior defined in reduction.rs.
1043    fn register_syn_lift(ctx: &mut Context) {
1044        let syntax = Term::Global("Syntax".to_string());
1045        let int = Term::Global("Int".to_string());
1046
1047        // syn_lift : Int -> Int -> Syntax -> Syntax
1048        let syn_lift_type = Term::Pi {
1049            param: "_".to_string(),
1050            param_type: Box::new(int.clone()),
1051            body_type: Box::new(Term::Pi {
1052                param: "_".to_string(),
1053                param_type: Box::new(int),
1054                body_type: Box::new(Term::Pi {
1055                    param: "_".to_string(),
1056                    param_type: Box::new(syntax.clone()),
1057                    body_type: Box::new(syntax),
1058                }),
1059            }),
1060        };
1061
1062        ctx.add_declaration("syn_lift", syn_lift_type);
1063    }
1064
1065    /// syn_subst : Syntax -> Int -> Syntax -> Syntax
1066    ///
1067    /// Substitutes replacement for variable at index in term.
1068    /// - syn_subst replacement index term
1069    /// - If term is SVar k and k == index, return replacement
1070    /// - If term is SVar k and k != index, return term unchanged
1071    /// - For binders, increment index and lift replacement
1072    /// Computational behavior defined in reduction.rs.
1073    fn register_syn_subst(ctx: &mut Context) {
1074        let syntax = Term::Global("Syntax".to_string());
1075        let int = Term::Global("Int".to_string());
1076
1077        // syn_subst : Syntax -> Int -> Syntax -> Syntax
1078        let syn_subst_type = Term::Pi {
1079            param: "_".to_string(),
1080            param_type: Box::new(syntax.clone()),
1081            body_type: Box::new(Term::Pi {
1082                param: "_".to_string(),
1083                param_type: Box::new(int),
1084                body_type: Box::new(Term::Pi {
1085                    param: "_".to_string(),
1086                    param_type: Box::new(syntax.clone()),
1087                    body_type: Box::new(syntax),
1088                }),
1089            }),
1090        };
1091
1092        ctx.add_declaration("syn_subst", syn_subst_type);
1093    }
1094
1095    // -------------------------------------------------------------------------
1096    // Beta Reduction (Computation)
1097    // -------------------------------------------------------------------------
1098
1099    /// syn_beta : Syntax -> Syntax -> Syntax
1100    ///
1101    /// Beta reduction: substitute arg for variable 0 in body.
1102    /// - syn_beta body arg = syn_subst arg 0 body
1103    /// Computational behavior defined in reduction.rs.
1104    fn register_syn_beta(ctx: &mut Context) {
1105        let syntax = Term::Global("Syntax".to_string());
1106
1107        // syn_beta : Syntax -> Syntax -> Syntax
1108        let syn_beta_type = Term::Pi {
1109            param: "_".to_string(),
1110            param_type: Box::new(syntax.clone()),
1111            body_type: Box::new(Term::Pi {
1112                param: "_".to_string(),
1113                param_type: Box::new(syntax.clone()),
1114                body_type: Box::new(syntax),
1115            }),
1116        };
1117
1118        ctx.add_declaration("syn_beta", syn_beta_type);
1119    }
1120
1121    /// syn_step : Syntax -> Syntax
1122    ///
1123    /// Single-step head reduction. Finds first beta redex and reduces.
1124    /// - If SApp (SLam T body) arg: perform beta reduction
1125    /// - If SApp f x where f is reducible: reduce f
1126    /// - Otherwise: return unchanged (stuck or value)
1127    /// Computational behavior defined in reduction.rs.
1128    fn register_syn_step(ctx: &mut Context) {
1129        let syntax = Term::Global("Syntax".to_string());
1130
1131        // syn_step : Syntax -> Syntax
1132        let syn_step_type = Term::Pi {
1133            param: "_".to_string(),
1134            param_type: Box::new(syntax.clone()),
1135            body_type: Box::new(syntax),
1136        };
1137
1138        ctx.add_declaration("syn_step", syn_step_type);
1139    }
1140
1141    // -------------------------------------------------------------------------
1142    // Bounded Evaluation
1143    // -------------------------------------------------------------------------
1144
1145    /// syn_eval : Int -> Syntax -> Syntax
1146    ///
1147    /// Bounded evaluation: reduce for up to N steps.
1148    /// - syn_eval fuel term
1149    /// - If fuel <= 0: return term unchanged
1150    /// - Otherwise: step and repeat until normal form or fuel exhausted
1151    /// Computational behavior defined in reduction.rs.
1152    fn register_syn_eval(ctx: &mut Context) {
1153        let syntax = Term::Global("Syntax".to_string());
1154        let int = Term::Global("Int".to_string());
1155
1156        // syn_eval : Int -> Syntax -> Syntax
1157        let syn_eval_type = Term::Pi {
1158            param: "_".to_string(),
1159            param_type: Box::new(int),
1160            body_type: Box::new(Term::Pi {
1161                param: "_".to_string(),
1162                param_type: Box::new(syntax.clone()),
1163                body_type: Box::new(syntax),
1164            }),
1165        };
1166
1167        ctx.add_declaration("syn_eval", syn_eval_type);
1168    }
1169
1170    // -------------------------------------------------------------------------
1171    // Reification (Quote)
1172    // -------------------------------------------------------------------------
1173
1174    /// syn_quote : Syntax -> Syntax
1175    ///
1176    /// Converts a Syntax value to Syntax code that constructs it.
1177    /// Computational behavior defined in reduction.rs.
1178    fn register_syn_quote(ctx: &mut Context) {
1179        let syntax = Term::Global("Syntax".to_string());
1180
1181        // syn_quote : Syntax -> Syntax
1182        let syn_quote_type = Term::Pi {
1183            param: "_".to_string(),
1184            param_type: Box::new(syntax.clone()),
1185            body_type: Box::new(syntax),
1186        };
1187
1188        ctx.add_declaration("syn_quote", syn_quote_type);
1189    }
1190
1191    // -------------------------------------------------------------------------
1192    // Diagonalization (Self-Reference)
1193    // -------------------------------------------------------------------------
1194
1195    /// syn_diag : Syntax -> Syntax
1196    ///
1197    /// The diagonal function: syn_diag x = syn_subst (syn_quote x) 0 x
1198    /// This is the key construction for self-reference and the diagonal lemma.
1199    fn register_syn_diag(ctx: &mut Context) {
1200        let syntax = Term::Global("Syntax".to_string());
1201
1202        let syn_diag_type = Term::Pi {
1203            param: "_".to_string(),
1204            param_type: Box::new(syntax.clone()),
1205            body_type: Box::new(syntax),
1206        };
1207
1208        ctx.add_declaration("syn_diag", syn_diag_type);
1209    }
1210
1211    // -------------------------------------------------------------------------
1212    // Inference Rules (Proof Trees)
1213    // -------------------------------------------------------------------------
1214
1215    /// Derivation : Type 0 (deep embedding of proof trees)
1216    ///
1217    /// DAxiom : Syntax -> Derivation (introduce an axiom)
1218    /// DModusPonens : Derivation -> Derivation -> Derivation (A->B, A |- B)
1219    /// DUnivIntro : Derivation -> Derivation (P(x) |- forall x. P(x))
1220    /// DUnivElim : Derivation -> Syntax -> Derivation (forall x. P(x), t |- P(t))
1221    fn register_derivation(ctx: &mut Context) {
1222        let syntax = Term::Global("Syntax".to_string());
1223        let derivation = Term::Global("Derivation".to_string());
1224
1225        // Derivation : Type 0
1226        ctx.add_inductive("Derivation", Term::Sort(Universe::Type(0)));
1227
1228        // DAxiom : Syntax -> Derivation
1229        ctx.add_constructor(
1230            "DAxiom",
1231            "Derivation",
1232            Term::Pi {
1233                param: "_".to_string(),
1234                param_type: Box::new(syntax.clone()),
1235                body_type: Box::new(derivation.clone()),
1236            },
1237        );
1238
1239        // DModusPonens : Derivation -> Derivation -> Derivation
1240        ctx.add_constructor(
1241            "DModusPonens",
1242            "Derivation",
1243            Term::Pi {
1244                param: "_".to_string(),
1245                param_type: Box::new(derivation.clone()),
1246                body_type: Box::new(Term::Pi {
1247                    param: "_".to_string(),
1248                    param_type: Box::new(derivation.clone()),
1249                    body_type: Box::new(derivation.clone()),
1250                }),
1251            },
1252        );
1253
1254        // DUnivIntro : Derivation -> Derivation
1255        ctx.add_constructor(
1256            "DUnivIntro",
1257            "Derivation",
1258            Term::Pi {
1259                param: "_".to_string(),
1260                param_type: Box::new(derivation.clone()),
1261                body_type: Box::new(derivation.clone()),
1262            },
1263        );
1264
1265        // DUnivElim : Derivation -> Syntax -> Derivation
1266        ctx.add_constructor(
1267            "DUnivElim",
1268            "Derivation",
1269            Term::Pi {
1270                param: "_".to_string(),
1271                param_type: Box::new(derivation.clone()),
1272                body_type: Box::new(Term::Pi {
1273                    param: "_".to_string(),
1274                    param_type: Box::new(syntax.clone()),
1275                    body_type: Box::new(derivation.clone()),
1276                }),
1277            },
1278        );
1279
1280        // DRefl : Syntax -> Syntax -> Derivation
1281        // DRefl T a proves (Eq T a a)
1282        ctx.add_constructor(
1283            "DRefl",
1284            "Derivation",
1285            Term::Pi {
1286                param: "_".to_string(),
1287                param_type: Box::new(syntax.clone()),
1288                body_type: Box::new(Term::Pi {
1289                    param: "_".to_string(),
1290                    param_type: Box::new(syntax.clone()),
1291                    body_type: Box::new(derivation.clone()),
1292                }),
1293            },
1294        );
1295
1296        // DInduction : Syntax -> Derivation -> Derivation -> Derivation
1297        // DInduction motive base step proves (∀n:Nat. motive n) via induction
1298        // - motive: λn:Nat. P(n) as Syntax
1299        // - base: proof of P(Zero)
1300        // - step: proof of ∀k:Nat. P(k) → P(Succ k)
1301        ctx.add_constructor(
1302            "DInduction",
1303            "Derivation",
1304            Term::Pi {
1305                param: "_".to_string(),
1306                param_type: Box::new(syntax.clone()), // motive
1307                body_type: Box::new(Term::Pi {
1308                    param: "_".to_string(),
1309                    param_type: Box::new(derivation.clone()), // base proof
1310                    body_type: Box::new(Term::Pi {
1311                        param: "_".to_string(),
1312                        param_type: Box::new(derivation.clone()), // step proof
1313                        body_type: Box::new(derivation.clone()),
1314                    }),
1315                }),
1316            },
1317        );
1318
1319        // DCompute : Syntax -> Derivation
1320        // DCompute goal proves goal by computation
1321        // - Validates that goal is (Eq T A B) and eval(A) == eval(B)
1322        ctx.add_constructor(
1323            "DCompute",
1324            "Derivation",
1325            Term::Pi {
1326                param: "_".to_string(),
1327                param_type: Box::new(syntax.clone()),
1328                body_type: Box::new(derivation.clone()),
1329            },
1330        );
1331
1332        // DCong : Syntax -> Derivation -> Derivation
1333        // DCong context eq_proof proves congruence
1334        // - context: SLam T body (function with hole at SVar 0)
1335        // - eq_proof: proof of (Eq T a b)
1336        // - Result: proof of (Eq T (body[0:=a]) (body[0:=b]))
1337        ctx.add_constructor(
1338            "DCong",
1339            "Derivation",
1340            Term::Pi {
1341                param: "_".to_string(),
1342                param_type: Box::new(syntax.clone()), // context
1343                body_type: Box::new(Term::Pi {
1344                    param: "_".to_string(),
1345                    param_type: Box::new(derivation.clone()), // eq_proof
1346                    body_type: Box::new(derivation.clone()),
1347                }),
1348            },
1349        );
1350
1351        // DCase : Derivation -> Derivation -> Derivation
1352        // Cons cell for case proofs in DElim
1353        ctx.add_constructor(
1354            "DCase",
1355            "Derivation",
1356            Term::Pi {
1357                param: "_".to_string(),
1358                param_type: Box::new(derivation.clone()), // head (case proof)
1359                body_type: Box::new(Term::Pi {
1360                    param: "_".to_string(),
1361                    param_type: Box::new(derivation.clone()), // tail (rest of cases)
1362                    body_type: Box::new(derivation.clone()),
1363                }),
1364            },
1365        );
1366
1367        // DCaseEnd : Derivation
1368        // Nil for case proofs in DElim
1369        ctx.add_constructor("DCaseEnd", "Derivation", derivation.clone());
1370
1371        // DElim : Syntax -> Syntax -> Derivation -> Derivation
1372        // Generic elimination for any inductive type
1373        // - ind_type: the inductive type (e.g., SName "Nat" or SApp (SName "List") A)
1374        // - motive: SLam param_type body (the property to prove)
1375        // - cases: DCase chain with one proof per constructor
1376        ctx.add_constructor(
1377            "DElim",
1378            "Derivation",
1379            Term::Pi {
1380                param: "_".to_string(),
1381                param_type: Box::new(syntax.clone()), // ind_type
1382                body_type: Box::new(Term::Pi {
1383                    param: "_".to_string(),
1384                    param_type: Box::new(syntax.clone()), // motive
1385                    body_type: Box::new(Term::Pi {
1386                        param: "_".to_string(),
1387                        param_type: Box::new(derivation.clone()), // cases
1388                        body_type: Box::new(derivation.clone()),
1389                    }),
1390                }),
1391            },
1392        );
1393
1394        // DInversion : Syntax -> Derivation
1395        // Proves False when no constructor can build the given hypothesis.
1396        // - hyp_type: the Syntax representation of the hypothesis (e.g., SApp (SName "Even") three)
1397        // - Returns proof of False if verified that all constructors are impossible
1398        ctx.add_constructor(
1399            "DInversion",
1400            "Derivation",
1401            Term::Pi {
1402                param: "_".to_string(),
1403                param_type: Box::new(syntax.clone()),
1404                body_type: Box::new(derivation.clone()),
1405            },
1406        );
1407
1408        // DRewrite : Derivation -> Syntax -> Syntax -> Derivation
1409        // Stores: eq_proof, original_goal, new_goal
1410        // Given eq_proof : Eq A x y, rewrites goal by replacing x with y
1411        ctx.add_constructor(
1412            "DRewrite",
1413            "Derivation",
1414            Term::Pi {
1415                param: "_".to_string(),
1416                param_type: Box::new(derivation.clone()), // eq_proof
1417                body_type: Box::new(Term::Pi {
1418                    param: "_".to_string(),
1419                    param_type: Box::new(syntax.clone()), // original_goal
1420                    body_type: Box::new(Term::Pi {
1421                        param: "_".to_string(),
1422                        param_type: Box::new(syntax.clone()), // new_goal
1423                        body_type: Box::new(derivation.clone()),
1424                    }),
1425                }),
1426            },
1427        );
1428
1429        // DDestruct : Syntax -> Syntax -> Derivation -> Derivation
1430        // Case analysis without induction hypotheses
1431        // - ind_type: the inductive type
1432        // - motive: the property to prove
1433        // - cases: DCase chain with proofs for each constructor
1434        ctx.add_constructor(
1435            "DDestruct",
1436            "Derivation",
1437            Term::Pi {
1438                param: "_".to_string(),
1439                param_type: Box::new(syntax.clone()), // ind_type
1440                body_type: Box::new(Term::Pi {
1441                    param: "_".to_string(),
1442                    param_type: Box::new(syntax.clone()), // motive
1443                    body_type: Box::new(Term::Pi {
1444                        param: "_".to_string(),
1445                        param_type: Box::new(derivation.clone()), // cases
1446                        body_type: Box::new(derivation.clone()),
1447                    }),
1448                }),
1449            },
1450        );
1451
1452        // DApply : Syntax -> Derivation -> Syntax -> Syntax -> Derivation
1453        // Manual backward chaining
1454        // - hyp_name: name of hypothesis
1455        // - hyp_proof: proof of the hypothesis
1456        // - original_goal: the goal we started with
1457        // - new_goal: the antecedent we need to prove
1458        ctx.add_constructor(
1459            "DApply",
1460            "Derivation",
1461            Term::Pi {
1462                param: "_".to_string(),
1463                param_type: Box::new(syntax.clone()), // hyp_name
1464                body_type: Box::new(Term::Pi {
1465                    param: "_".to_string(),
1466                    param_type: Box::new(derivation.clone()), // hyp_proof
1467                    body_type: Box::new(Term::Pi {
1468                        param: "_".to_string(),
1469                        param_type: Box::new(syntax.clone()), // original_goal
1470                        body_type: Box::new(Term::Pi {
1471                            param: "_".to_string(),
1472                            param_type: Box::new(syntax), // new_goal
1473                            body_type: Box::new(derivation),
1474                        }),
1475                    }),
1476                }),
1477            },
1478        );
1479    }
1480
1481    /// concludes : Derivation -> Syntax
1482    ///
1483    /// Extracts the conclusion from a derivation.
1484    /// Computational behavior defined in reduction.rs.
1485    fn register_concludes(ctx: &mut Context) {
1486        let derivation = Term::Global("Derivation".to_string());
1487        let syntax = Term::Global("Syntax".to_string());
1488
1489        // concludes : Derivation -> Syntax
1490        let concludes_type = Term::Pi {
1491            param: "_".to_string(),
1492            param_type: Box::new(derivation),
1493            body_type: Box::new(syntax),
1494        };
1495
1496        ctx.add_declaration("concludes", concludes_type);
1497    }
1498
1499    // -------------------------------------------------------------------------
1500    // Core Tactics
1501    // -------------------------------------------------------------------------
1502
1503    /// try_refl : Syntax -> Derivation
1504    ///
1505    /// Reflexivity tactic: given a goal, try to prove it by reflexivity.
1506    /// - If goal matches (Eq T a b) and a == b, returns DRefl T a
1507    /// - Otherwise returns DAxiom (SName "Error")
1508    /// Computational behavior defined in reduction.rs.
1509    fn register_try_refl(ctx: &mut Context) {
1510        let syntax = Term::Global("Syntax".to_string());
1511        let derivation = Term::Global("Derivation".to_string());
1512
1513        // try_refl : Syntax -> Derivation
1514        let try_refl_type = Term::Pi {
1515            param: "_".to_string(),
1516            param_type: Box::new(syntax),
1517            body_type: Box::new(derivation),
1518        };
1519
1520        ctx.add_declaration("try_refl", try_refl_type);
1521    }
1522
1523    /// try_compute : Syntax -> Derivation
1524    ///
1525    /// Computation tactic: given a goal (Eq T A B), proves it by evaluating
1526    /// both sides and checking equality.
1527    /// Returns DCompute goal.
1528    /// Computational behavior defined in reduction.rs.
1529    fn register_try_compute(ctx: &mut Context) {
1530        let syntax = Term::Global("Syntax".to_string());
1531        let derivation = Term::Global("Derivation".to_string());
1532
1533        // try_compute : Syntax -> Derivation
1534        let try_compute_type = Term::Pi {
1535            param: "_".to_string(),
1536            param_type: Box::new(syntax),
1537            body_type: Box::new(derivation),
1538        };
1539
1540        ctx.add_declaration("try_compute", try_compute_type);
1541    }
1542
1543    /// try_cong : Syntax -> Derivation -> Derivation
1544    ///
1545    /// Congruence tactic: given a context (SLam T body) and proof of (Eq T a b),
1546    /// produces proof of (Eq T (body[0:=a]) (body[0:=b])).
1547    /// Returns DCong context eq_proof.
1548    /// Computational behavior defined in reduction.rs.
1549    fn register_try_cong(ctx: &mut Context) {
1550        let syntax = Term::Global("Syntax".to_string());
1551        let derivation = Term::Global("Derivation".to_string());
1552
1553        // try_cong : Syntax -> Derivation -> Derivation
1554        let try_cong_type = Term::Pi {
1555            param: "_".to_string(),
1556            param_type: Box::new(syntax), // context
1557            body_type: Box::new(Term::Pi {
1558                param: "_".to_string(),
1559                param_type: Box::new(derivation.clone()), // eq_proof
1560                body_type: Box::new(derivation),
1561            }),
1562        };
1563
1564        ctx.add_declaration("try_cong", try_cong_type);
1565    }
1566
1567    // -------------------------------------------------------------------------
1568    // Tactic Combinators
1569    // -------------------------------------------------------------------------
1570
1571    /// tact_fail : Syntax -> Derivation
1572    ///
1573    /// A tactic that always fails by returning DAxiom (SName "Error").
1574    /// Useful for testing combinators and as a base case.
1575    /// Computational behavior defined in reduction.rs.
1576    fn register_tact_fail(ctx: &mut Context) {
1577        let syntax = Term::Global("Syntax".to_string());
1578        let derivation = Term::Global("Derivation".to_string());
1579
1580        // tact_fail : Syntax -> Derivation
1581        let tact_fail_type = Term::Pi {
1582            param: "_".to_string(),
1583            param_type: Box::new(syntax),
1584            body_type: Box::new(derivation),
1585        };
1586
1587        ctx.add_declaration("tact_fail", tact_fail_type);
1588    }
1589
1590    /// tact_orelse : (Syntax -> Derivation) -> (Syntax -> Derivation) -> Syntax -> Derivation
1591    ///
1592    /// Tactic combinator: try first tactic, if it fails (concludes to Error) try second.
1593    /// Enables composition of tactics with fallback behavior.
1594    /// Computational behavior defined in reduction.rs.
1595    fn register_tact_orelse(ctx: &mut Context) {
1596        let syntax = Term::Global("Syntax".to_string());
1597        let derivation = Term::Global("Derivation".to_string());
1598
1599        // Tactic type: Syntax -> Derivation
1600        let tactic_type = Term::Pi {
1601            param: "_".to_string(),
1602            param_type: Box::new(syntax.clone()),
1603            body_type: Box::new(derivation.clone()),
1604        };
1605
1606        // tact_orelse : (Syntax -> Derivation) -> (Syntax -> Derivation) -> Syntax -> Derivation
1607        let tact_orelse_type = Term::Pi {
1608            param: "_".to_string(),
1609            param_type: Box::new(tactic_type.clone()), // t1
1610            body_type: Box::new(Term::Pi {
1611                param: "_".to_string(),
1612                param_type: Box::new(tactic_type), // t2
1613                body_type: Box::new(Term::Pi {
1614                    param: "_".to_string(),
1615                    param_type: Box::new(syntax), // goal
1616                    body_type: Box::new(derivation),
1617                }),
1618            }),
1619        };
1620
1621        ctx.add_declaration("tact_orelse", tact_orelse_type);
1622    }
1623
1624    /// tact_try : (Syntax -> Derivation) -> Syntax -> Derivation
1625    ///
1626    /// Tactic combinator: try the tactic, but never fail.
1627    /// If the tactic fails (concludes to Error), return identity (DAxiom goal).
1628    /// Computational behavior defined in reduction.rs.
1629    fn register_tact_try(ctx: &mut Context) {
1630        let syntax = Term::Global("Syntax".to_string());
1631        let derivation = Term::Global("Derivation".to_string());
1632
1633        // Tactic type: Syntax -> Derivation
1634        let tactic_type = Term::Pi {
1635            param: "_".to_string(),
1636            param_type: Box::new(syntax.clone()),
1637            body_type: Box::new(derivation.clone()),
1638        };
1639
1640        // tact_try : (Syntax -> Derivation) -> Syntax -> Derivation
1641        let tact_try_type = Term::Pi {
1642            param: "_".to_string(),
1643            param_type: Box::new(tactic_type), // t
1644            body_type: Box::new(Term::Pi {
1645                param: "_".to_string(),
1646                param_type: Box::new(syntax),
1647                body_type: Box::new(derivation),
1648            }),
1649        };
1650
1651        ctx.add_declaration("tact_try", tact_try_type);
1652    }
1653
1654    /// tact_repeat : (Syntax -> Derivation) -> Syntax -> Derivation
1655    ///
1656    /// Tactic combinator: apply tactic repeatedly until it fails or makes no progress.
1657    /// Returns identity if tactic fails immediately.
1658    /// Computational behavior defined in reduction.rs.
1659    fn register_tact_repeat(ctx: &mut Context) {
1660        let syntax = Term::Global("Syntax".to_string());
1661        let derivation = Term::Global("Derivation".to_string());
1662
1663        // Tactic type: Syntax -> Derivation
1664        let tactic_type = Term::Pi {
1665            param: "_".to_string(),
1666            param_type: Box::new(syntax.clone()),
1667            body_type: Box::new(derivation.clone()),
1668        };
1669
1670        // tact_repeat : (Syntax -> Derivation) -> Syntax -> Derivation
1671        let tact_repeat_type = Term::Pi {
1672            param: "_".to_string(),
1673            param_type: Box::new(tactic_type), // t
1674            body_type: Box::new(Term::Pi {
1675                param: "_".to_string(),
1676                param_type: Box::new(syntax),
1677                body_type: Box::new(derivation),
1678            }),
1679        };
1680
1681        ctx.add_declaration("tact_repeat", tact_repeat_type);
1682    }
1683
1684    /// tact_then : (Syntax -> Derivation) -> (Syntax -> Derivation) -> Syntax -> Derivation
1685    ///
1686    /// Tactic combinator: sequence two tactics (the ";" operator).
1687    /// Apply t1 to goal, then apply t2 to the result.
1688    /// Fails if either tactic fails.
1689    /// Computational behavior defined in reduction.rs.
1690    fn register_tact_then(ctx: &mut Context) {
1691        let syntax = Term::Global("Syntax".to_string());
1692        let derivation = Term::Global("Derivation".to_string());
1693
1694        // Tactic type: Syntax -> Derivation
1695        let tactic_type = Term::Pi {
1696            param: "_".to_string(),
1697            param_type: Box::new(syntax.clone()),
1698            body_type: Box::new(derivation.clone()),
1699        };
1700
1701        // tact_then : (Syntax -> Derivation) -> (Syntax -> Derivation) -> Syntax -> Derivation
1702        let tact_then_type = Term::Pi {
1703            param: "_".to_string(),
1704            param_type: Box::new(tactic_type.clone()), // t1
1705            body_type: Box::new(Term::Pi {
1706                param: "_".to_string(),
1707                param_type: Box::new(tactic_type), // t2
1708                body_type: Box::new(Term::Pi {
1709                    param: "_".to_string(),
1710                    param_type: Box::new(syntax),
1711                    body_type: Box::new(derivation),
1712                }),
1713            }),
1714        };
1715
1716        ctx.add_declaration("tact_then", tact_then_type);
1717    }
1718
1719    /// tact_first : TList (Syntax -> Derivation) -> Syntax -> Derivation
1720    ///
1721    /// Tactic combinator: try tactics from a list until one succeeds.
1722    /// Returns Error if all tactics fail or list is empty.
1723    /// Computational behavior defined in reduction.rs.
1724    fn register_tact_first(ctx: &mut Context) {
1725        let syntax = Term::Global("Syntax".to_string());
1726        let derivation = Term::Global("Derivation".to_string());
1727
1728        // Tactic type: Syntax -> Derivation
1729        let tactic_type = Term::Pi {
1730            param: "_".to_string(),
1731            param_type: Box::new(syntax.clone()),
1732            body_type: Box::new(derivation.clone()),
1733        };
1734
1735        // TList (Syntax -> Derivation)
1736        let tactic_list_type = Term::App(
1737            Box::new(Term::Global("TList".to_string())),
1738            Box::new(tactic_type),
1739        );
1740
1741        // tact_first : TList (Syntax -> Derivation) -> Syntax -> Derivation
1742        let tact_first_type = Term::Pi {
1743            param: "_".to_string(),
1744            param_type: Box::new(tactic_list_type), // tactics
1745            body_type: Box::new(Term::Pi {
1746                param: "_".to_string(),
1747                param_type: Box::new(syntax),
1748                body_type: Box::new(derivation),
1749            }),
1750        };
1751
1752        ctx.add_declaration("tact_first", tact_first_type);
1753    }
1754
1755    /// tact_solve : (Syntax -> Derivation) -> Syntax -> Derivation
1756    ///
1757    /// Tactic combinator: tactic MUST completely solve the goal.
1758    /// If tactic returns Error, returns Error.
1759    /// If tactic returns a proof, returns that proof.
1760    /// Computational behavior defined in reduction.rs.
1761    fn register_tact_solve(ctx: &mut Context) {
1762        let syntax = Term::Global("Syntax".to_string());
1763        let derivation = Term::Global("Derivation".to_string());
1764
1765        // Tactic type: Syntax -> Derivation
1766        let tactic_type = Term::Pi {
1767            param: "_".to_string(),
1768            param_type: Box::new(syntax.clone()),
1769            body_type: Box::new(derivation.clone()),
1770        };
1771
1772        // tact_solve : (Syntax -> Derivation) -> Syntax -> Derivation
1773        let tact_solve_type = Term::Pi {
1774            param: "_".to_string(),
1775            param_type: Box::new(tactic_type), // t
1776            body_type: Box::new(Term::Pi {
1777                param: "_".to_string(),
1778                param_type: Box::new(syntax),
1779                body_type: Box::new(derivation),
1780            }),
1781        };
1782
1783        ctx.add_declaration("tact_solve", tact_solve_type);
1784    }
1785
1786    // -------------------------------------------------------------------------
1787    // Ring Tactic (Polynomial Equality)
1788    // -------------------------------------------------------------------------
1789
1790    /// DRingSolve : Syntax -> Derivation
1791    /// try_ring : Syntax -> Derivation
1792    ///
1793    /// Ring tactic: proves polynomial equalities by normalization.
1794    /// Computational behavior defined in reduction.rs.
1795    fn register_try_ring(ctx: &mut Context) {
1796        let syntax = Term::Global("Syntax".to_string());
1797        let derivation = Term::Global("Derivation".to_string());
1798
1799        // DRingSolve : Syntax -> Derivation
1800        // Proof constructor for ring-solved equalities
1801        ctx.add_constructor(
1802            "DRingSolve",
1803            "Derivation",
1804            Term::Pi {
1805                param: "_".to_string(),
1806                param_type: Box::new(syntax.clone()),
1807                body_type: Box::new(derivation.clone()),
1808            },
1809        );
1810
1811        // try_ring : Syntax -> Derivation
1812        // Ring tactic: given a goal, try to prove it by polynomial normalization
1813        let try_ring_type = Term::Pi {
1814            param: "_".to_string(),
1815            param_type: Box::new(syntax),
1816            body_type: Box::new(derivation),
1817        };
1818
1819        ctx.add_declaration("try_ring", try_ring_type);
1820    }
1821
1822    // -------------------------------------------------------------------------
1823    // LIA Tactic (Linear Integer Arithmetic)
1824    // -------------------------------------------------------------------------
1825
1826    /// DLiaSolve : Syntax -> Derivation
1827    /// try_lia : Syntax -> Derivation
1828    ///
1829    /// LIA tactic: proves linear inequalities by Fourier-Motzkin elimination.
1830    /// Computational behavior defined in reduction.rs.
1831    fn register_try_lia(ctx: &mut Context) {
1832        let syntax = Term::Global("Syntax".to_string());
1833        let derivation = Term::Global("Derivation".to_string());
1834
1835        // DLiaSolve : Syntax -> Derivation
1836        // Proof constructor for LIA-solved inequalities
1837        ctx.add_constructor(
1838            "DLiaSolve",
1839            "Derivation",
1840            Term::Pi {
1841                param: "_".to_string(),
1842                param_type: Box::new(syntax.clone()),
1843                body_type: Box::new(derivation.clone()),
1844            },
1845        );
1846
1847        // try_lia : Syntax -> Derivation
1848        // LIA tactic: given a goal, try to prove it by linear arithmetic
1849        let try_lia_type = Term::Pi {
1850            param: "_".to_string(),
1851            param_type: Box::new(syntax),
1852            body_type: Box::new(derivation),
1853        };
1854
1855        ctx.add_declaration("try_lia", try_lia_type);
1856    }
1857
1858    /// DccSolve : Syntax -> Derivation
1859    /// try_cc : Syntax -> Derivation
1860    ///
1861    /// Congruence Closure tactic: proves equalities over uninterpreted functions.
1862    /// Handles hypotheses via implications: (implies (Eq x y) (Eq (f x) (f y)))
1863    /// Computational behavior defined in reduction.rs.
1864    fn register_try_cc(ctx: &mut Context) {
1865        let syntax = Term::Global("Syntax".to_string());
1866        let derivation = Term::Global("Derivation".to_string());
1867
1868        // DccSolve : Syntax -> Derivation
1869        // Proof constructor for congruence closure proofs
1870        ctx.add_constructor(
1871            "DccSolve",
1872            "Derivation",
1873            Term::Pi {
1874                param: "_".to_string(),
1875                param_type: Box::new(syntax.clone()),
1876                body_type: Box::new(derivation.clone()),
1877            },
1878        );
1879
1880        // try_cc : Syntax -> Derivation
1881        // CC tactic: given a goal, try to prove it by congruence closure
1882        let try_cc_type = Term::Pi {
1883            param: "_".to_string(),
1884            param_type: Box::new(syntax),
1885            body_type: Box::new(derivation),
1886        };
1887
1888        ctx.add_declaration("try_cc", try_cc_type);
1889    }
1890
1891    /// DSimpSolve : Syntax -> Derivation
1892    /// try_simp : Syntax -> Derivation
1893    ///
1894    /// Simplifier tactic: proves equalities by term rewriting.
1895    /// Uses bottom-up rewriting with arithmetic evaluation and hypothesis substitution.
1896    /// Handles: reflexivity, constant folding (2+3=5), and hypothesis-based substitution.
1897    /// Computational behavior defined in reduction.rs.
1898    fn register_try_simp(ctx: &mut Context) {
1899        let syntax = Term::Global("Syntax".to_string());
1900        let derivation = Term::Global("Derivation".to_string());
1901
1902        // DSimpSolve : Syntax -> Derivation
1903        // Proof constructor for simplifier proofs
1904        ctx.add_constructor(
1905            "DSimpSolve",
1906            "Derivation",
1907            Term::Pi {
1908                param: "_".to_string(),
1909                param_type: Box::new(syntax.clone()),
1910                body_type: Box::new(derivation.clone()),
1911            },
1912        );
1913
1914        // try_simp : Syntax -> Derivation
1915        // Simp tactic: given a goal, try to prove it by simplification
1916        let try_simp_type = Term::Pi {
1917            param: "_".to_string(),
1918            param_type: Box::new(syntax),
1919            body_type: Box::new(derivation),
1920        };
1921
1922        ctx.add_declaration("try_simp", try_simp_type);
1923    }
1924
1925    /// DOmegaSolve : Syntax -> Derivation
1926    /// try_omega : Syntax -> Derivation
1927    ///
1928    /// Omega tactic: proves linear integer arithmetic with proper floor/ceil rounding.
1929    /// Unlike lia (which uses rationals), omega handles integers correctly:
1930    /// - x > 1 means x >= 2 (strict-to-nonstrict conversion)
1931    /// - 3x <= 10 means x <= 3 (floor division)
1932    /// Computational behavior defined in reduction.rs.
1933    fn register_try_omega(ctx: &mut Context) {
1934        let syntax = Term::Global("Syntax".to_string());
1935        let derivation = Term::Global("Derivation".to_string());
1936
1937        // DOmegaSolve : Syntax -> Derivation
1938        // Proof constructor for omega-solved inequalities
1939        ctx.add_constructor(
1940            "DOmegaSolve",
1941            "Derivation",
1942            Term::Pi {
1943                param: "_".to_string(),
1944                param_type: Box::new(syntax.clone()),
1945                body_type: Box::new(derivation.clone()),
1946            },
1947        );
1948
1949        // try_omega : Syntax -> Derivation
1950        // Omega tactic: given a goal, try to prove it by integer arithmetic
1951        let try_omega_type = Term::Pi {
1952            param: "_".to_string(),
1953            param_type: Box::new(syntax),
1954            body_type: Box::new(derivation),
1955        };
1956
1957        ctx.add_declaration("try_omega", try_omega_type);
1958    }
1959
1960    /// DAutoSolve : Syntax -> Derivation
1961    /// try_auto : Syntax -> Derivation
1962    ///
1963    /// Auto tactic: tries all decision procedures in sequence.
1964    /// Order: simp → ring → cc → omega → lia
1965    /// Returns the first successful derivation, or error if all fail.
1966    /// Computational behavior defined in reduction.rs.
1967    fn register_try_auto(ctx: &mut Context) {
1968        let syntax = Term::Global("Syntax".to_string());
1969        let derivation = Term::Global("Derivation".to_string());
1970
1971        // DAutoSolve : Syntax -> Derivation
1972        // Proof constructor for auto-solved goals
1973        ctx.add_constructor(
1974            "DAutoSolve",
1975            "Derivation",
1976            Term::Pi {
1977                param: "_".to_string(),
1978                param_type: Box::new(syntax.clone()),
1979                body_type: Box::new(derivation.clone()),
1980            },
1981        );
1982
1983        // try_auto : Syntax -> Derivation
1984        // Auto tactic: given a goal, try all tactics in sequence
1985        let try_auto_type = Term::Pi {
1986            param: "_".to_string(),
1987            param_type: Box::new(syntax),
1988            body_type: Box::new(derivation),
1989        };
1990
1991        ctx.add_declaration("try_auto", try_auto_type);
1992    }
1993
1994    /// try_induction : Syntax -> Syntax -> Derivation -> Derivation
1995    ///
1996    /// Generic induction tactic for any inductive type.
1997    /// Arguments:
1998    /// - ind_type: The inductive type (SName "Nat" or SApp (SName "List") A)
1999    /// - motive: The property to prove (SLam param_type body)
2000    /// - cases: DCase chain with one derivation per constructor
2001    ///
2002    /// Returns a DElim derivation if verification passes.
2003    fn register_try_induction(ctx: &mut Context) {
2004        let syntax = Term::Global("Syntax".to_string());
2005        let derivation = Term::Global("Derivation".to_string());
2006
2007        // try_induction : Syntax -> Syntax -> Derivation -> Derivation
2008        let try_induction_type = Term::Pi {
2009            param: "_".to_string(),
2010            param_type: Box::new(syntax.clone()), // ind_type
2011            body_type: Box::new(Term::Pi {
2012                param: "_".to_string(),
2013                param_type: Box::new(syntax.clone()), // motive
2014                body_type: Box::new(Term::Pi {
2015                    param: "_".to_string(),
2016                    param_type: Box::new(derivation.clone()), // cases
2017                    body_type: Box::new(derivation),
2018                }),
2019            }),
2020        };
2021
2022        ctx.add_declaration("try_induction", try_induction_type);
2023    }
2024
2025    /// Helper functions for building induction goals.
2026    ///
2027    /// These functions help construct the subgoals for induction:
2028    /// - induction_base_goal: Computes the base case goal
2029    /// - induction_step_goal: Computes the step case goal for a constructor
2030    /// - induction_num_cases: Returns number of constructors for an inductive
2031    fn register_induction_helpers(ctx: &mut Context) {
2032        let syntax = Term::Global("Syntax".to_string());
2033        let nat = Term::Global("Nat".to_string());
2034
2035        // induction_base_goal : Syntax -> Syntax -> Syntax
2036        // Given ind_type and motive, returns the base case goal (first constructor)
2037        ctx.add_declaration(
2038            "induction_base_goal",
2039            Term::Pi {
2040                param: "_".to_string(),
2041                param_type: Box::new(syntax.clone()),
2042                body_type: Box::new(Term::Pi {
2043                    param: "_".to_string(),
2044                    param_type: Box::new(syntax.clone()),
2045                    body_type: Box::new(syntax.clone()),
2046                }),
2047            },
2048        );
2049
2050        // induction_step_goal : Syntax -> Syntax -> Nat -> Syntax
2051        // Given ind_type, motive, constructor index, returns the case goal
2052        ctx.add_declaration(
2053            "induction_step_goal",
2054            Term::Pi {
2055                param: "_".to_string(),
2056                param_type: Box::new(syntax.clone()),
2057                body_type: Box::new(Term::Pi {
2058                    param: "_".to_string(),
2059                    param_type: Box::new(syntax.clone()),
2060                    body_type: Box::new(Term::Pi {
2061                        param: "_".to_string(),
2062                        param_type: Box::new(nat),
2063                        body_type: Box::new(syntax.clone()),
2064                    }),
2065                }),
2066            },
2067        );
2068
2069        // induction_num_cases : Syntax -> Nat
2070        // Returns number of constructors for an inductive type
2071        ctx.add_declaration(
2072            "induction_num_cases",
2073            Term::Pi {
2074                param: "_".to_string(),
2075                param_type: Box::new(syntax),
2076                body_type: Box::new(Term::Global("Nat".to_string())),
2077            },
2078        );
2079    }
2080
2081    // -------------------------------------------------------------------------
2082    // Inversion Tactic
2083    // -------------------------------------------------------------------------
2084
2085    /// try_inversion : Syntax -> Derivation
2086    ///
2087    /// Inversion tactic: given a hypothesis type, derives False if no constructor
2088    /// can possibly build that type.
2089    ///
2090    /// Example: try_inversion (SApp (SName "Even") three) proves False because
2091    /// neither even_zero (requires 0) nor even_succ (requires Even 1) can build Even 3.
2092    ///
2093    /// Computational behavior defined in reduction.rs.
2094    fn register_try_inversion_tactic(ctx: &mut Context) {
2095        let syntax = Term::Global("Syntax".to_string());
2096        let derivation = Term::Global("Derivation".to_string());
2097
2098        // try_inversion : Syntax -> Derivation
2099        ctx.add_declaration(
2100            "try_inversion",
2101            Term::Pi {
2102                param: "_".to_string(),
2103                param_type: Box::new(syntax),
2104                body_type: Box::new(derivation),
2105            },
2106        );
2107    }
2108
2109    // -------------------------------------------------------------------------
2110    // Operator Tactics (rewrite, destruct, apply)
2111    // -------------------------------------------------------------------------
2112
2113    /// Operator tactics for manual proof control.
2114    ///
2115    /// try_rewrite : Derivation -> Syntax -> Derivation
2116    /// try_rewrite_rev : Derivation -> Syntax -> Derivation
2117    /// try_destruct : Syntax -> Syntax -> Derivation -> Derivation
2118    /// try_apply : Syntax -> Derivation -> Syntax -> Derivation
2119    fn register_operator_tactics(ctx: &mut Context) {
2120        let syntax = Term::Global("Syntax".to_string());
2121        let derivation = Term::Global("Derivation".to_string());
2122
2123        // try_rewrite : Derivation -> Syntax -> Derivation
2124        // Given eq_proof (concluding Eq A x y) and goal, replaces x with y in goal
2125        ctx.add_declaration(
2126            "try_rewrite",
2127            Term::Pi {
2128                param: "_".to_string(),
2129                param_type: Box::new(derivation.clone()), // eq_proof
2130                body_type: Box::new(Term::Pi {
2131                    param: "_".to_string(),
2132                    param_type: Box::new(syntax.clone()), // goal
2133                    body_type: Box::new(derivation.clone()),
2134                }),
2135            },
2136        );
2137
2138        // try_rewrite_rev : Derivation -> Syntax -> Derivation
2139        // Given eq_proof (concluding Eq A x y) and goal, replaces y with x in goal (reverse direction)
2140        ctx.add_declaration(
2141            "try_rewrite_rev",
2142            Term::Pi {
2143                param: "_".to_string(),
2144                param_type: Box::new(derivation.clone()), // eq_proof
2145                body_type: Box::new(Term::Pi {
2146                    param: "_".to_string(),
2147                    param_type: Box::new(syntax.clone()), // goal
2148                    body_type: Box::new(derivation.clone()),
2149                }),
2150            },
2151        );
2152
2153        // try_destruct : Syntax -> Syntax -> Derivation -> Derivation
2154        // Case analysis without induction hypotheses
2155        ctx.add_declaration(
2156            "try_destruct",
2157            Term::Pi {
2158                param: "_".to_string(),
2159                param_type: Box::new(syntax.clone()), // ind_type
2160                body_type: Box::new(Term::Pi {
2161                    param: "_".to_string(),
2162                    param_type: Box::new(syntax.clone()), // motive
2163                    body_type: Box::new(Term::Pi {
2164                        param: "_".to_string(),
2165                        param_type: Box::new(derivation.clone()), // cases
2166                        body_type: Box::new(derivation.clone()),
2167                    }),
2168                }),
2169            },
2170        );
2171
2172        // try_apply : Syntax -> Derivation -> Syntax -> Derivation
2173        // Manual backward chaining - applies hypothesis to transform goal
2174        ctx.add_declaration(
2175            "try_apply",
2176            Term::Pi {
2177                param: "_".to_string(),
2178                param_type: Box::new(syntax.clone()), // hyp_name
2179                body_type: Box::new(Term::Pi {
2180                    param: "_".to_string(),
2181                    param_type: Box::new(derivation.clone()), // hyp_proof
2182                    body_type: Box::new(Term::Pi {
2183                        param: "_".to_string(),
2184                        param_type: Box::new(syntax), // goal
2185                        body_type: Box::new(derivation),
2186                    }),
2187                }),
2188            },
2189        );
2190    }
2191
2192    // =========================================================================
2193    // HARDWARE TACTICS: try_bitblast, try_tabulate, try_hw_auto
2194    // =========================================================================
2195
2196    fn register_hw_tactics(ctx: &mut Context) {
2197        let syntax = Term::Global("Syntax".to_string());
2198        let derivation = Term::Global("Derivation".to_string());
2199
2200        // DBitblastSolve : Syntax -> Derivation
2201        ctx.add_constructor(
2202            "DBitblastSolve",
2203            "Derivation",
2204            Term::Pi {
2205                param: "_".to_string(),
2206                param_type: Box::new(syntax.clone()),
2207                body_type: Box::new(derivation.clone()),
2208            },
2209        );
2210
2211        // try_bitblast : Syntax -> Derivation
2212        ctx.add_declaration(
2213            "try_bitblast",
2214            Term::Pi {
2215                param: "_".to_string(),
2216                param_type: Box::new(syntax.clone()),
2217                body_type: Box::new(derivation.clone()),
2218            },
2219        );
2220
2221        // DTabulateSolve : Syntax -> Derivation
2222        ctx.add_constructor(
2223            "DTabulateSolve",
2224            "Derivation",
2225            Term::Pi {
2226                param: "_".to_string(),
2227                param_type: Box::new(syntax.clone()),
2228                body_type: Box::new(derivation.clone()),
2229            },
2230        );
2231
2232        // try_tabulate : Syntax -> Derivation
2233        ctx.add_declaration(
2234            "try_tabulate",
2235            Term::Pi {
2236                param: "_".to_string(),
2237                param_type: Box::new(syntax.clone()),
2238                body_type: Box::new(derivation.clone()),
2239            },
2240        );
2241
2242        // DHwAutoSolve : Syntax -> Derivation
2243        ctx.add_constructor(
2244            "DHwAutoSolve",
2245            "Derivation",
2246            Term::Pi {
2247                param: "_".to_string(),
2248                param_type: Box::new(syntax.clone()),
2249                body_type: Box::new(derivation.clone()),
2250            },
2251        );
2252
2253        // try_hw_auto : Syntax -> Derivation
2254        ctx.add_declaration(
2255            "try_hw_auto",
2256            Term::Pi {
2257                param: "_".to_string(),
2258                param_type: Box::new(syntax.clone()),
2259                body_type: Box::new(derivation),
2260            },
2261        );
2262    }
2263
2264    // =========================================================================
2265    // HARDWARE TYPES: Bit, Unit, BVec, gate operations, Circuit, BVec ops
2266    // =========================================================================
2267
2268    /// Register all hardware-related types and operations.
2269    fn register_hardware(ctx: &mut Context) {
2270        Self::register_bit(ctx);
2271        Self::register_hw_unit(ctx);
2272        Self::register_bvec(ctx);
2273        Self::register_gate_ops(ctx);
2274        Self::register_circuit(ctx);
2275        Self::register_bvec_ops(ctx);
2276    }
2277
2278    /// Bit : Type 0 — 1-bit logic value
2279    /// B0 : Bit — logic low
2280    /// B1 : Bit — logic high
2281    fn register_bit(ctx: &mut Context) {
2282        let bit = Term::Global("Bit".to_string());
2283        ctx.add_inductive("Bit", Term::Sort(Universe::Type(0)));
2284        ctx.add_constructor("B0", "Bit", bit.clone());
2285        ctx.add_constructor("B1", "Bit", bit);
2286    }
2287
2288    /// Unit : Type 0 — trivial type for stateless circuits
2289    /// Tt : Unit — sole inhabitant
2290    fn register_hw_unit(ctx: &mut Context) {
2291        let unit = Term::Global("Unit".to_string());
2292        ctx.add_inductive("Unit", Term::Sort(Universe::Type(0)));
2293        ctx.add_constructor("Tt", "Unit", unit);
2294    }
2295
2296    /// BVec : Nat -> Type 0 — length-indexed bitvector
2297    /// BVNil : BVec Zero
2298    /// BVCons : Bit -> Π(n:Nat). BVec n -> BVec (Succ n)
2299    fn register_bvec(ctx: &mut Context) {
2300        let type0 = Term::Sort(Universe::Type(0));
2301        let nat = Term::Global("Nat".to_string());
2302        let n = Term::Var("n".to_string());
2303
2304        // BVec : Nat -> Type 0
2305        let bvec_type = Term::Pi {
2306            param: "n".to_string(),
2307            param_type: Box::new(nat.clone()),
2308            body_type: Box::new(type0),
2309        };
2310        ctx.add_inductive("BVec", bvec_type);
2311
2312        // BVNil : BVec Zero
2313        let bvec_zero = Term::App(
2314            Box::new(Term::Global("BVec".to_string())),
2315            Box::new(Term::Global("Zero".to_string())),
2316        );
2317        ctx.add_constructor("BVNil", "BVec", bvec_zero);
2318
2319        // BVCons : Bit -> Π(n:Nat). BVec n -> BVec (Succ n)
2320        let bit = Term::Global("Bit".to_string());
2321        let bvec_n = Term::App(
2322            Box::new(Term::Global("BVec".to_string())),
2323            Box::new(n.clone()),
2324        );
2325        let bvec_succ_n = Term::App(
2326            Box::new(Term::Global("BVec".to_string())),
2327            Box::new(Term::App(
2328                Box::new(Term::Global("Succ".to_string())),
2329                Box::new(n.clone()),
2330            )),
2331        );
2332        let bvcons_type = Term::Pi {
2333            param: "_".to_string(),
2334            param_type: Box::new(bit),
2335            body_type: Box::new(Term::Pi {
2336                param: "n".to_string(),
2337                param_type: Box::new(nat),
2338                body_type: Box::new(Term::Pi {
2339                    param: "_".to_string(),
2340                    param_type: Box::new(bvec_n),
2341                    body_type: Box::new(bvec_succ_n),
2342                }),
2343            }),
2344        };
2345        ctx.add_constructor("BVCons", "BVec", bvcons_type);
2346    }
2347
2348    /// Gate operations as transparent definitions (unfold via iota reduction).
2349    ///
2350    /// bit_and : Bit -> Bit -> Bit — match a: B0 -> B0, B1 -> b
2351    /// bit_or  : Bit -> Bit -> Bit — match a: B0 -> b,  B1 -> B1
2352    /// bit_not : Bit -> Bit        — match a: B0 -> B1, B1 -> B0
2353    /// bit_xor : Bit -> Bit -> Bit — match a: B0 -> bit_not b, B1 -> b
2354    /// bit_mux : Bit -> Bit -> Bit -> Bit — match sel: B0 -> else, B1 -> then
2355    fn register_gate_ops(ctx: &mut Context) {
2356        let bit = Term::Global("Bit".to_string());
2357
2358        // Bit -> Bit -> Bit
2359        let bit2_type = Term::Pi {
2360            param: "_".to_string(),
2361            param_type: Box::new(bit.clone()),
2362            body_type: Box::new(Term::Pi {
2363                param: "_".to_string(),
2364                param_type: Box::new(bit.clone()),
2365                body_type: Box::new(bit.clone()),
2366            }),
2367        };
2368
2369        // Bit -> Bit
2370        let bit1_type = Term::Pi {
2371            param: "_".to_string(),
2372            param_type: Box::new(bit.clone()),
2373            body_type: Box::new(bit.clone()),
2374        };
2375
2376        // Bit -> Bit -> Bit -> Bit
2377        let bit3_type = Term::Pi {
2378            param: "_".to_string(),
2379            param_type: Box::new(bit.clone()),
2380            body_type: Box::new(Term::Pi {
2381                param: "_".to_string(),
2382                param_type: Box::new(bit.clone()),
2383                body_type: Box::new(Term::Pi {
2384                    param: "_".to_string(),
2385                    param_type: Box::new(bit.clone()),
2386                    body_type: Box::new(bit.clone()),
2387                }),
2388            }),
2389        };
2390
2391        // Motive for match on Bit: λ(_:Bit). Bit
2392        let motive = Term::Lambda {
2393            param: "_".to_string(),
2394            param_type: Box::new(bit.clone()),
2395            body: Box::new(bit.clone()),
2396        };
2397
2398        // bit_and := λ(a:Bit). λ(b:Bit). match a return (λ_:Bit. Bit) with [B0, b]
2399        let bit_and_body = Term::Lambda {
2400            param: "a".to_string(),
2401            param_type: Box::new(bit.clone()),
2402            body: Box::new(Term::Lambda {
2403                param: "b".to_string(),
2404                param_type: Box::new(bit.clone()),
2405                body: Box::new(Term::Match {
2406                    discriminant: Box::new(Term::Var("a".to_string())),
2407                    motive: Box::new(motive.clone()),
2408                    cases: vec![
2409                        Term::Global("B0".to_string()), // B0 case: return B0
2410                        Term::Var("b".to_string()),      // B1 case: return b
2411                    ],
2412                }),
2413            }),
2414        };
2415        ctx.add_definition("bit_and".to_string(), bit2_type.clone(), bit_and_body);
2416
2417        // bit_or := λ(a:Bit). λ(b:Bit). match a return (λ_:Bit. Bit) with [b, B1]
2418        let bit_or_body = Term::Lambda {
2419            param: "a".to_string(),
2420            param_type: Box::new(bit.clone()),
2421            body: Box::new(Term::Lambda {
2422                param: "b".to_string(),
2423                param_type: Box::new(bit.clone()),
2424                body: Box::new(Term::Match {
2425                    discriminant: Box::new(Term::Var("a".to_string())),
2426                    motive: Box::new(motive.clone()),
2427                    cases: vec![
2428                        Term::Var("b".to_string()),      // B0 case: return b
2429                        Term::Global("B1".to_string()), // B1 case: return B1
2430                    ],
2431                }),
2432            }),
2433        };
2434        ctx.add_definition("bit_or".to_string(), bit2_type.clone(), bit_or_body);
2435
2436        // bit_not := λ(a:Bit). match a return (λ_:Bit. Bit) with [B1, B0]
2437        let bit_not_body = Term::Lambda {
2438            param: "a".to_string(),
2439            param_type: Box::new(bit.clone()),
2440            body: Box::new(Term::Match {
2441                discriminant: Box::new(Term::Var("a".to_string())),
2442                motive: Box::new(motive.clone()),
2443                cases: vec![
2444                    Term::Global("B1".to_string()), // B0 case: return B1
2445                    Term::Global("B0".to_string()), // B1 case: return B0
2446                ],
2447            }),
2448        };
2449        ctx.add_definition("bit_not".to_string(), bit1_type, bit_not_body);
2450
2451        // bit_xor := λ(a:Bit). λ(b:Bit). match a return (λ_:Bit. Bit) with [b, bit_not b]
2452        // XOR truth table: 0^0=0, 0^1=1, 1^0=1, 1^1=0
2453        // When a=B0: result = b (0^0=0, 0^1=1)
2454        // When a=B1: result = bit_not b (1^0=1, 1^1=0)
2455        let bit_xor_body = Term::Lambda {
2456            param: "a".to_string(),
2457            param_type: Box::new(bit.clone()),
2458            body: Box::new(Term::Lambda {
2459                param: "b".to_string(),
2460                param_type: Box::new(bit.clone()),
2461                body: Box::new(Term::Match {
2462                    discriminant: Box::new(Term::Var("a".to_string())),
2463                    motive: Box::new(motive.clone()),
2464                    cases: vec![
2465                        // B0 case: b
2466                        Term::Var("b".to_string()),
2467                        // B1 case: bit_not b
2468                        Term::App(
2469                            Box::new(Term::Global("bit_not".to_string())),
2470                            Box::new(Term::Var("b".to_string())),
2471                        ),
2472                    ],
2473                }),
2474            }),
2475        };
2476        ctx.add_definition("bit_xor".to_string(), bit2_type, bit_xor_body);
2477
2478        // bit_mux := λ(sel:Bit). λ(then_v:Bit). λ(else_v:Bit).
2479        //            match sel return (λ_:Bit. Bit) with [else_v, then_v]
2480        let bit_mux_body = Term::Lambda {
2481            param: "sel".to_string(),
2482            param_type: Box::new(bit.clone()),
2483            body: Box::new(Term::Lambda {
2484                param: "then_v".to_string(),
2485                param_type: Box::new(bit.clone()),
2486                body: Box::new(Term::Lambda {
2487                    param: "else_v".to_string(),
2488                    param_type: Box::new(bit.clone()),
2489                    body: Box::new(Term::Match {
2490                        discriminant: Box::new(Term::Var("sel".to_string())),
2491                        motive: Box::new(motive),
2492                        cases: vec![
2493                            Term::Var("else_v".to_string()), // B0 case: else
2494                            Term::Var("then_v".to_string()), // B1 case: then
2495                        ],
2496                    }),
2497                }),
2498            }),
2499        };
2500        ctx.add_definition("bit_mux".to_string(), bit3_type, bit_mux_body);
2501    }
2502
2503    /// Circuit : Type 0 -> Type 0 -> Type 0 -> Type 0
2504    /// MkCircuit : Π(S:Type 0). Π(I:Type 0). Π(O:Type 0).
2505    ///             (S -> I -> S) -> (S -> I -> O) -> S -> Circuit S I O
2506    fn register_circuit(ctx: &mut Context) {
2507        let type0 = Term::Sort(Universe::Type(0));
2508        let s = Term::Var("S".to_string());
2509        let i = Term::Var("I".to_string());
2510        let o = Term::Var("O".to_string());
2511
2512        // Circuit : Type 0 -> Type 0 -> Type 0 -> Type 0
2513        let circuit_type = Term::Pi {
2514            param: "S".to_string(),
2515            param_type: Box::new(type0.clone()),
2516            body_type: Box::new(Term::Pi {
2517                param: "I".to_string(),
2518                param_type: Box::new(type0.clone()),
2519                body_type: Box::new(Term::Pi {
2520                    param: "O".to_string(),
2521                    param_type: Box::new(type0.clone()),
2522                    body_type: Box::new(type0.clone()),
2523                }),
2524            }),
2525        };
2526        ctx.add_inductive("Circuit", circuit_type);
2527
2528        // Circuit S I O
2529        let circuit_s_i_o = Term::App(
2530            Box::new(Term::App(
2531                Box::new(Term::App(
2532                    Box::new(Term::Global("Circuit".to_string())),
2533                    Box::new(s.clone()),
2534                )),
2535                Box::new(i.clone()),
2536            )),
2537            Box::new(o.clone()),
2538        );
2539
2540        // S -> I -> S (transition function type)
2541        let trans_type = Term::Pi {
2542            param: "_".to_string(),
2543            param_type: Box::new(s.clone()),
2544            body_type: Box::new(Term::Pi {
2545                param: "_".to_string(),
2546                param_type: Box::new(i.clone()),
2547                body_type: Box::new(s.clone()),
2548            }),
2549        };
2550
2551        // S -> I -> O (output function type)
2552        let out_type = Term::Pi {
2553            param: "_".to_string(),
2554            param_type: Box::new(s.clone()),
2555            body_type: Box::new(Term::Pi {
2556                param: "_".to_string(),
2557                param_type: Box::new(i.clone()),
2558                body_type: Box::new(o.clone()),
2559            }),
2560        };
2561
2562        // MkCircuit : Π(S:Type0). Π(I:Type0). Π(O:Type0).
2563        //             (S->I->S) -> (S->I->O) -> S -> Circuit S I O
2564        let mkcircuit_type = Term::Pi {
2565            param: "S".to_string(),
2566            param_type: Box::new(type0.clone()),
2567            body_type: Box::new(Term::Pi {
2568                param: "I".to_string(),
2569                param_type: Box::new(type0.clone()),
2570                body_type: Box::new(Term::Pi {
2571                    param: "O".to_string(),
2572                    param_type: Box::new(type0),
2573                    body_type: Box::new(Term::Pi {
2574                        param: "_".to_string(),
2575                        param_type: Box::new(trans_type),
2576                        body_type: Box::new(Term::Pi {
2577                            param: "_".to_string(),
2578                            param_type: Box::new(out_type),
2579                            body_type: Box::new(Term::Pi {
2580                                param: "_".to_string(),
2581                                param_type: Box::new(s),
2582                                body_type: Box::new(circuit_s_i_o),
2583                            }),
2584                        }),
2585                    }),
2586                }),
2587            }),
2588        };
2589        ctx.add_constructor("MkCircuit", "Circuit", mkcircuit_type);
2590    }
2591
2592    /// Bitvector operations as recursive Fix definitions.
2593    /// bv_and, bv_or, bv_not, bv_xor : Π(n:Nat). BVec n -> BVec n -> BVec n
2594    fn register_bvec_ops(ctx: &mut Context) {
2595        let nat = Term::Global("Nat".to_string());
2596        let n = Term::Var("n".to_string());
2597        let bvec_n = Term::App(
2598            Box::new(Term::Global("BVec".to_string())),
2599            Box::new(n.clone()),
2600        );
2601
2602        // Π(n:Nat). BVec n -> BVec n -> BVec n
2603        let bv_binop_type = Term::Pi {
2604            param: "n".to_string(),
2605            param_type: Box::new(nat.clone()),
2606            body_type: Box::new(Term::Pi {
2607                param: "_".to_string(),
2608                param_type: Box::new(bvec_n.clone()),
2609                body_type: Box::new(Term::Pi {
2610                    param: "_".to_string(),
2611                    param_type: Box::new(bvec_n.clone()),
2612                    body_type: Box::new(bvec_n.clone()),
2613                }),
2614            }),
2615        };
2616
2617        // Π(n:Nat). BVec n -> BVec n
2618        let bv_unop_type = Term::Pi {
2619            param: "n".to_string(),
2620            param_type: Box::new(nat.clone()),
2621            body_type: Box::new(Term::Pi {
2622                param: "_".to_string(),
2623                param_type: Box::new(bvec_n.clone()),
2624                body_type: Box::new(bvec_n.clone()),
2625            }),
2626        };
2627
2628        // Helper: build BVec m
2629        let bvec_of = |m: Term| -> Term {
2630            Term::App(Box::new(Term::Global("BVec".to_string())), Box::new(m))
2631        };
2632
2633        // Motive for Match on BVec n: λ(_:BVec n). BVec n
2634        // (In practice, the motive parameter is unused, so a simple identity type works)
2635        let motive_n = Term::Lambda {
2636            param: "_".to_string(),
2637            param_type: Box::new(bvec_n.clone()),
2638            body: Box::new(bvec_n.clone()),
2639        };
2640
2641        // --- bv_and ---
2642        // fix bv_and_rec. λ(n:Nat). λ(v1:BVec n). λ(v2:BVec n).
2643        //   match v1 with
2644        //   | BVNil => BVNil
2645        //   | BVCons => λ(b1:Bit). λ(m:Nat). λ(tail1:BVec m).
2646        //       match v2 with
2647        //       | BVNil => BVNil
2648        //       | BVCons => λ(b2:Bit). λ(_:Nat). λ(tail2:BVec m).
2649        //           BVCons (bit_and b1 b2) m (bv_and_rec m tail1 tail2)
2650        let bit = Term::Global("Bit".to_string());
2651
2652        let bv_and_body = Self::make_bvec_binop_fix(
2653            "bv_and_rec", "bit_and", &nat, &bvec_n, &bit, &motive_n,
2654        );
2655        ctx.add_definition("bv_and".to_string(), bv_binop_type.clone(), bv_and_body);
2656
2657        // --- bv_or ---
2658        let bv_or_body = Self::make_bvec_binop_fix(
2659            "bv_or_rec", "bit_or", &nat, &bvec_n, &bit, &motive_n,
2660        );
2661        ctx.add_definition("bv_or".to_string(), bv_binop_type.clone(), bv_or_body);
2662
2663        // --- bv_xor ---
2664        let bv_xor_body = Self::make_bvec_binop_fix(
2665            "bv_xor_rec", "bit_xor", &nat, &bvec_n, &bit, &motive_n,
2666        );
2667        ctx.add_definition("bv_xor".to_string(), bv_binop_type, bv_xor_body);
2668
2669        // --- bv_not ---
2670        // fix bv_not_rec. λ(n:Nat). λ(v:BVec n).
2671        //   match v with
2672        //   | BVNil => BVNil
2673        //   | BVCons => λ(b:Bit). λ(m:Nat). λ(tail:BVec m).
2674        //       BVCons (bit_not b) m (bv_not_rec m tail)
2675        let bv_not_body = Self::make_bvec_unop_fix(
2676            "bv_not_rec", "bit_not", &nat, &bvec_n, &bit, &motive_n,
2677        );
2678        ctx.add_definition("bv_not".to_string(), bv_unop_type, bv_not_body);
2679    }
2680
2681    /// Build a Fix term for a binary BVec operation (bv_and, bv_or, bv_xor).
2682    ///
2683    /// Pattern: fix rec. λn. λv1. λv2. match v1 { BVNil => BVNil, BVCons b1 m t1 => match v2 { BVNil => BVNil, BVCons b2 _ t2 => BVCons (bit_op b1 b2) m (rec m t1 t2) } }
2684    fn make_bvec_binop_fix(
2685        rec_name: &str,
2686        bit_op: &str,
2687        nat: &Term,
2688        bvec_n: &Term,
2689        bit: &Term,
2690        motive: &Term,
2691    ) -> Term {
2692        let m_var = Term::Var("m".to_string());
2693        let bvec_m = Term::App(Box::new(Term::Global("BVec".to_string())), Box::new(m_var.clone()));
2694        let motive_m = Term::Lambda {
2695            param: "_".to_string(),
2696            param_type: Box::new(bvec_m.clone()),
2697            body: Box::new(bvec_m.clone()),
2698        };
2699
2700        // Innermost: BVCons (bit_op b1 b2) m (rec m tail1 tail2)
2701        let bit_op_applied = Term::App(
2702            Box::new(Term::App(
2703                Box::new(Term::Global(bit_op.to_string())),
2704                Box::new(Term::Var("b1".to_string())),
2705            )),
2706            Box::new(Term::Var("b2".to_string())),
2707        );
2708        let rec_call = Term::App(
2709            Box::new(Term::App(
2710                Box::new(Term::App(
2711                    Box::new(Term::Var(rec_name.to_string())),
2712                    Box::new(m_var.clone()),
2713                )),
2714                Box::new(Term::Var("tail1".to_string())),
2715            )),
2716            Box::new(Term::Var("tail2".to_string())),
2717        );
2718        let bvcons_result = Term::App(
2719            Box::new(Term::App(
2720                Box::new(Term::App(
2721                    Box::new(Term::Global("BVCons".to_string())),
2722                    Box::new(bit_op_applied),
2723                )),
2724                Box::new(m_var.clone()),
2725            )),
2726            Box::new(rec_call),
2727        );
2728
2729        // Inner match on v2 (BVCons case for v1)
2730        let inner_bvcons_case = Term::Lambda {
2731            param: "b2".to_string(),
2732            param_type: Box::new(bit.clone()),
2733            body: Box::new(Term::Lambda {
2734                param: "_m2".to_string(),
2735                param_type: Box::new(nat.clone()),
2736                body: Box::new(Term::Lambda {
2737                    param: "tail2".to_string(),
2738                    param_type: Box::new(bvec_m.clone()),
2739                    body: Box::new(bvcons_result),
2740                }),
2741            }),
2742        };
2743
2744        let inner_match = Term::Match {
2745            discriminant: Box::new(Term::Var("v2".to_string())),
2746            motive: Box::new(motive_m.clone()),
2747            cases: vec![
2748                Term::Global("BVNil".to_string()), // BVNil case
2749                inner_bvcons_case,                  // BVCons case
2750            ],
2751        };
2752
2753        // Outer BVCons case for v1
2754        let outer_bvcons_case = Term::Lambda {
2755            param: "b1".to_string(),
2756            param_type: Box::new(bit.clone()),
2757            body: Box::new(Term::Lambda {
2758                param: "m".to_string(),
2759                param_type: Box::new(nat.clone()),
2760                body: Box::new(Term::Lambda {
2761                    param: "tail1".to_string(),
2762                    param_type: Box::new(bvec_m.clone()),
2763                    body: Box::new(inner_match),
2764                }),
2765            }),
2766        };
2767
2768        // Outer match on v1
2769        let outer_match = Term::Match {
2770            discriminant: Box::new(Term::Var("v1".to_string())),
2771            motive: Box::new(motive.clone()),
2772            cases: vec![
2773                Term::Global("BVNil".to_string()), // BVNil case
2774                outer_bvcons_case,                  // BVCons case
2775            ],
2776        };
2777
2778        // Fix + lambdas
2779        Term::Fix {
2780            name: rec_name.to_string(),
2781            body: Box::new(Term::Lambda {
2782                param: "n".to_string(),
2783                param_type: Box::new(nat.clone()),
2784                body: Box::new(Term::Lambda {
2785                    param: "v1".to_string(),
2786                    param_type: Box::new(bvec_n.clone()),
2787                    body: Box::new(Term::Lambda {
2788                        param: "v2".to_string(),
2789                        param_type: Box::new(bvec_n.clone()),
2790                        body: Box::new(outer_match),
2791                    }),
2792                }),
2793            }),
2794        }
2795    }
2796
2797    /// Build a Fix term for a unary BVec operation (bv_not).
2798    ///
2799    /// Pattern: fix rec. λn. λv. match v { BVNil => BVNil, BVCons b m t => BVCons (bit_op b) m (rec m t) }
2800    fn make_bvec_unop_fix(
2801        rec_name: &str,
2802        bit_op: &str,
2803        nat: &Term,
2804        bvec_n: &Term,
2805        bit: &Term,
2806        motive: &Term,
2807    ) -> Term {
2808        let m_var = Term::Var("m".to_string());
2809        let bvec_m = Term::App(Box::new(Term::Global("BVec".to_string())), Box::new(m_var.clone()));
2810
2811        // BVCons (bit_op b) m (rec m tail)
2812        let bit_op_applied = Term::App(
2813            Box::new(Term::Global(bit_op.to_string())),
2814            Box::new(Term::Var("b".to_string())),
2815        );
2816        let rec_call = Term::App(
2817            Box::new(Term::App(
2818                Box::new(Term::Var(rec_name.to_string())),
2819                Box::new(m_var.clone()),
2820            )),
2821            Box::new(Term::Var("tail".to_string())),
2822        );
2823        let bvcons_result = Term::App(
2824            Box::new(Term::App(
2825                Box::new(Term::App(
2826                    Box::new(Term::Global("BVCons".to_string())),
2827                    Box::new(bit_op_applied),
2828                )),
2829                Box::new(m_var.clone()),
2830            )),
2831            Box::new(rec_call),
2832        );
2833
2834        // BVCons case
2835        let bvcons_case = Term::Lambda {
2836            param: "b".to_string(),
2837            param_type: Box::new(bit.clone()),
2838            body: Box::new(Term::Lambda {
2839                param: "m".to_string(),
2840                param_type: Box::new(nat.clone()),
2841                body: Box::new(Term::Lambda {
2842                    param: "tail".to_string(),
2843                    param_type: Box::new(bvec_m),
2844                    body: Box::new(bvcons_result),
2845                }),
2846            }),
2847        };
2848
2849        // Match on v
2850        let match_expr = Term::Match {
2851            discriminant: Box::new(Term::Var("v".to_string())),
2852            motive: Box::new(motive.clone()),
2853            cases: vec![
2854                Term::Global("BVNil".to_string()), // BVNil case
2855                bvcons_case,                        // BVCons case
2856            ],
2857        };
2858
2859        // Fix + lambdas
2860        Term::Fix {
2861            name: rec_name.to_string(),
2862            body: Box::new(Term::Lambda {
2863                param: "n".to_string(),
2864                param_type: Box::new(nat.clone()),
2865                body: Box::new(Term::Lambda {
2866                    param: "v".to_string(),
2867                    param_type: Box::new(bvec_n.clone()),
2868                    body: Box::new(match_expr),
2869                }),
2870            }),
2871        }
2872    }
2873}