Section HILBERT_PROOF_SYSTEM.
#[local]
Tactic Notation "done" :=
first [congruence | lia | done!].
Context {L : language}.
Definition varcouples : forall n : nat, trms L n * trms L n :=
nat_rec (fun n => (trms L n * trms L n)%type) (O_trms, O_trms) (fun n => prod_rec _ (fun lhs => fun rhs => (S_trms n (Var_trm (n + n)) lhs, S_trms n (Var_trm (S (n + n))) rhs))).
Definition eqns_imp p : nat -> frm L :=
nat_rec (fun _ => frm L) p (fun n => fun q => Imp_frm (Eqn_frm (Var_trm (n + n)) (Var_trm (S (n + n)))) q).
Definition Fun_eqAxm (f : L.(function_symbols)) : frm L :=
eqns_imp (prod_rec (fun _ => frm L) (fun lhs => fun rhs => Eqn_frm (Fun_trm f lhs) (Fun_trm f rhs)) (varcouples (L.(function_arity_table) f))) (L.(function_arity_table) f).
Definition Rel_eqAxm (R : L.(relation_symbols)) : frm L :=
eqns_imp (prod_rec (fun _ => frm L) (fun lhs => fun rhs => Imp_frm (Rel_frm R lhs) (Rel_frm R rhs)) (varcouples (L.(relation_arity_table) R))) (L.(relation_arity_table) R).
Inductive proof : list (frm L) -> frm L -> Set := (* Reference: "https://github.com/princeton-vl/CoqGym/blob/master/coq_projects/goedel/folProof.v#L68" *)
| AXM p
: proof [p] p
| MP ps1 ps2 p q
(PF1 : proof ps1 (Imp_frm p q))
(PF2 : proof ps2 p)
: proof (ps1 ++ ps2) q
| GEN ps q x
(NOT_FREE : forall p, In p ps -> is_not_free_in_frm x p)
(PF : proof ps q)
: proof ps (All_frm x q)
| IMP1 p q
: proof [] (Imp_frm p (Imp_frm q p))
| IMP2 p q r
: proof [] (Imp_frm (Imp_frm p (Imp_frm q r)) (Imp_frm (Imp_frm p q) (Imp_frm p r)))
| CP p q
: proof [] (Imp_frm (Imp_frm (Neg_frm q) (Neg_frm p)) (Imp_frm p q))
| FA1 p x t
: proof [] (Imp_frm (All_frm x p) (subst_frm (one_subst x t) p))
| FA2 p x
(NOT_FREE : is_not_free_in_frm x p)
: proof [] (Imp_frm p (All_frm x p))
| FA3 p q x
: proof [] (Imp_frm (All_frm x (Imp_frm p q)) (Imp_frm (All_frm x p) (All_frm x q)))
| EQN_REFL
: proof [] (Eqn_frm (Var_trm 0) (Var_trm 0))
| EQN_SYM
: proof [] (Imp_frm (Eqn_frm (Var_trm 0) (Var_trm 1)) (Eqn_frm (Var_trm 1) (Var_trm 0)))
| EQN_TRANS
: proof [] (Imp_frm (Eqn_frm (Var_trm 0) (Var_trm 1)) (Imp_frm (Eqn_frm (Var_trm 1) (Var_trm 2)) (Eqn_frm (Var_trm 0) (Var_trm 2))))
| EQN_FUN f
: proof [] (Fun_eqAxm f)
| EQN_REL R
: proof [] (Rel_eqAxm R).
Definition proves (Gamma : ensemble (frm L)) (C : frm L) : Prop :=
exists ps, E.fromList ps \subseteq Gamma /\ inhabited (proof ps C).
#[local] Infix "\proves" := proves : type_scope.

Lemma proof_square (p1 : frm L) (p2 : frm L) (p3 : frm L) (p4 : frm L)
(PROOF1 : proof [] (Imp_frm p1 p2))
(PROOF2 : proof [] (Imp_frm p2 p3))
(PROOF3 : proof [] (Imp_frm p3 p4))
: proof [] (Imp_frm p1 p4).