Require Import List Arith Lia Max.
From Undecidability.Shared.Libs.DLW.Utils
Require Import utils_tac utils_list utils_nat.
From Undecidability.Shared.Libs.DLW.Vec
Require Import pos vec.
From Undecidability.TRAKHTENBROT
Require Import notations utils decidable enumerable
fol_ops fo_sig fo_terms fo_logic.
Import fol_notations.
Set Default Proof Using "Type".
Set Implicit Arguments.
Section fol_enumerable.
Variable (Σ : fo_signature)
(H1 : discrete (syms Σ))
(H2 : discrete (rels Σ))
(H3 : type_enum_t (syms Σ))
(H4 : type_enum_t (rels Σ)).
Let Hunit : opt_enum_t (fun _ : unit => True).
Proof.
apply type_enum_opt_enum_t.
exists (fun _ => Some tt).
intros []; exists 0; auto.
Qed.
Let Hnat : opt_enum_t (fun _ : nat => True).
Proof.
apply type_enum_opt_enum_t.
exists Some.
intros n; exists n; auto.
Qed.
Let Hfol_bop : opt_enum_t (fun _ : fol_bop => True).
Proof.
apply type_enum_opt_enum_t.
exists (fun n => Some (match n with 0 => fol_conj | 1 => fol_disj | _ => fol_imp end)).
intros [].
+ exists 0; auto.
+ exists 1; auto.
+ exists 2; auto.
Qed.
Let Hfol_qop : opt_enum_t (fun _ : fol_qop => True).
Proof.
apply type_enum_opt_enum_t.
exists (fun n => Some (match n with 0 => fol_fa | _ => fol_ex end)).
intros [].
+ exists 1; auto.
+ exists 0; auto.
Qed.
Lemma type_enum_t_fo_term : type_enum_t (fo_term (ar_syms Σ)).
Proof using H3 H1.
apply type_enum_t_by_measure with (m := @fo_term_height _ _).
induction n as [ | n Hn ].
+ generalize Hnat.
apply opt_enum_t_image with in_var.
intros [ i | s v ]; simpl.
* split; auto; exists i; auto.
* split; try lia; intros (? & _ & ?); discriminate.
+ generalize (opt_enum_t_dep_sum _ _ H1 H3 (fun s => opt_enum_t_vec (ar_syms Σ s) Hn)); intros H5.
generalize (opt_enum_t_sum Hnat H5).
apply opt_enum_t_image with
(f := fun p =>
match p with
| inl i => in_var i
| inr (existT _ s v) => @in_fot _ _ s v
end).
intros t; split.
* destruct t as [ i | s v ]; intros H.
- exists (inl i); auto.
- exists (inr (existT _ s v)); simpl; split; auto.
intros p; generalize (fo_term_height_lt _ v p); lia.
* intros ([ i | (s,v) ] & H); revert H; simpl.
- intros (_ & ->); simpl; lia.
- intros (G & ->); simpl; apply le_n_S, lmax_spec, Forall_forall.
intros x Hx; apply vec_list_inv in Hx.
destruct Hx as (p & Hp); revert Hp; rew vec; intros ->; auto.
Qed.
Theorem type_enum_t_fol_form : type_enum_t (fol_form Σ).
Proof using H4 H3 H2 H1.
apply type_enum_t_by_measure with (m := @fol_height _).
induction n as [ | n Hn ].
+ exists (fun n => None).
intros [ | | | ]; simpl; split; try lia; intros (? & ?); discriminate.
+ generalize type_enum_t_fo_term; intros H5.
apply type_enum_opt_enum_t in H5.
generalize (opt_enum_t_dep_sum _ _ H2 H4 (fun r => opt_enum_t_vec (ar_rels Σ r) H5)); intros H6.
generalize (opt_enum_t_prod Hfol_bop (opt_enum_t_prod Hn Hn)); intros H7.
generalize (opt_enum_t_prod Hfol_qop Hn); intros H8.
generalize (opt_enum_t_sum (opt_enum_t_sum Hunit H6) (opt_enum_t_sum H7 H8)).
apply opt_enum_t_image with
(f := fun p =>
match p with
| inl (inl _) => ⊥
| inl (inr (existT _ r v)) => fol_atom r v
| inr (inl (b,(A,B))) => fol_bin b A B
| inr (inr (q,A)) => fol_quant q A
end).
intros A; split.
* revert A; intros [ | r v | b A B | q A ]; simpl; intros H.
- exists (inl (inl tt)); auto.
- exists (inl (inr (existT _ r v))); simpl; auto.
- apply le_S_n in H.
exists (inr (inl (b,(A,B)))); simpl; repeat split; auto;
apply le_trans with (2 := H).
++ apply le_max_l.
++ apply le_max_r.
- apply le_S_n in H.
exists (inr (inr (q,A))); simpl; repeat split; auto.
* intros ([ [ [] | (r&v) ] | [ (b,(B,C)) | (q,B) ] ] & H); revert H; simpl.
- intros (_ & ->); simpl; lia.
- intros (_ & ->); simpl; lia.
- intros ((_ & G1 & G2) & ->); simpl.
apply le_n_S, max_lub; auto.
- intros ((_ & G1) & ->); simpl; lia.
Qed.
End fol_enumerable.