Require Import List Arith Lia Max Wellfounded Setoid Eqdep_dec Bool.
From Undecidability.Shared.Libs.DLW.Utils
Require Import utils_tac utils_list finite.
From Undecidability.Shared.Libs.DLW.Vec
Require Import pos vec.
From Undecidability.Shared.Libs.DLW.Wf
Require Import wf_finite wf_chains.
From Undecidability.TRAKHTENBROT
Require Import notations fol_ops membership btree.
Set Default Proof Using "Type".
Set Implicit Arguments.
Local Infix "⪧" := bt_node.
Section hfs.
Definition hfs : Set := sig (fun t => bt_norm t = t).
Definition bt_cls (t : bt) : hfs.
Proof. exists (bt_norm t); apply bt_norm_idem. Defined.
Arguments bt_cls t /.
Definition hfs_repr (s : hfs) := proj1_sig s.
Fact bt_norm_exist x y (E : x = y) (H1 : bt_norm x = x) (H2 : bt_norm y = y) : exist _ x H1 = exist _ y H2 :> hfs.
Proof. subst; f_equal; apply bt_eq_pirr. Qed.
Fact bt_cls_hfs_repr s : bt_cls (hfs_repr s) = s.
Proof.
destruct s as (t & Ht); simpl.
apply bt_norm_exist, Ht.
Qed.
Fact hfs_repr_bt_cls t : hfs_repr (bt_cls t) ≈ t.
Proof. apply bt_norm_eq. Qed.
Notation cls := bt_cls.
Notation repr := hfs_repr.
Fact bt_cls_eq_norm s t : bt_cls s = bt_cls t <-> bt_norm s = bt_norm t.
Proof.
simpl; split.
+ inversion 1; auto.
+ intro; apply bt_norm_exist; auto.
Qed.
Fact bt_cls_equiv s t : bt_cls s = bt_cls t <-> s ≈ t.
Proof.
rewrite bt_cls_eq_norm; split; apply bte_norm_iff.
Qed.
Fact bt_cls_hfs_repr_iff t s : cls t = s <-> t ≈ repr s.
Proof.
rewrite <- (bt_cls_hfs_repr s) at 1.
apply bt_cls_equiv.
Qed.
Definition hfs_eq_dec : forall (s t : hfs), { s = t } + { s <> t }.
Proof.
intros (s & Hs) (t & Ht).
destruct (bt_eq_dec s t) as [ H | H ].
+ left; subst; f_equal; apply bt_eq_pirr.
+ right; contradict H; inversion H; auto.
Qed.
Definition hfs_mem s t := bt_mem (repr s) (repr t).
Infix "∈" := hfs_mem.
Arguments hfs_mem s t /.
Fact btm_cls_repr t s : cls t ∈ s <-> bt_mem t (repr s).
Proof.
generalize (bt_norm_eq t).
simpl; split; apply btm_congr_l; auto.
Qed.
Fact btm_repr_cls t s : t ∈ cls s <-> bt_mem (repr t) s.
Proof.
generalize (bt_norm_eq s).
simpl; split; apply btm_congr_r; auto.
Qed.
Fact hfs_mem_btm s t : cls s ∈ cls t <-> bt_mem s t.
Proof. rewrite btm_repr_cls, hfs_repr_bt_cls; tauto. Qed.
Fact hfs_mem_repr s t : s ∈ t <-> bt_mem (repr s) (repr t).
Proof. tauto. Qed.
Fact hfs_mem_ext s t : s = t <-> forall x, x ∈ s <-> x ∈ t.
Proof.
rewrite <- (bt_cls_hfs_repr s), <- (bt_cls_hfs_repr t), bt_cls_equiv; simpl.
rewrite bte_ext; split; intros H.
+ revert s t H; intros (s & Hs) (t & Ht) H (x & Hx); simpl in *.
rewrite Hs, Ht; auto.
+ revert s t H; intros (s & Hs) (t & Ht) H x; simpl in *.
rewrite Hs, Ht in H.
specialize (H (bt_cls x)).
rewrite (hfs_repr_bt_cls x) in H; auto.
Qed.
Fact hfs_mem_wf : well_founded hfs_mem.
Proof. unfold hfs_mem; apply wf_inverse_image, btm_wf. Qed.
Definition hfs_rect := well_founded_induction_type hfs_mem_wf.
Fact hfs_mem_fin_t t : fin_t (fun s => s ∈ t).
Proof.
destruct (btm_finite_t (repr t)) as (l & Hl).
exists (map cls l).
intros x; simpl; rewrite Hl, in_map_iff; split.
+ intros (s & H1 & H2).
exists s; split; auto.
rewrite bt_cls_hfs_repr_iff; auto.
+ intros (s & H1 & H2).
exists s; split; auto.
rewrite bt_cls_hfs_repr_iff in H1; auto.
Qed.
Fact hfs_mem_dec : forall s t, { s ∈ t } + { ~ s ∈ t }.
Proof.
intros (s & ?) (t & ?); simpl; apply btm_dec.
Qed.
Definition hfs_empty : hfs := exist _ bt_leaf eq_refl.
Notation "∅" := hfs_empty.
Fact hfs_empty_prop : forall x, ~ x ∈ ∅.
Proof.
intros (x & ?); simpl; btm simpl.
Qed.
Fact hfs_empty_spec x : x ∈ ∅ <-> False.
Proof.
split; try tauto; apply hfs_empty_prop.
Qed.
Definition hfs_cons x t := cls ((repr x)⪧(repr t)).
Fact hfs_cons_spec y x t : y ∈ hfs_cons x t <-> y = x \/ y ∈ t.
Proof.
unfold hfs_cons.
rewrite btm_repr_cls; btm simpl.
fol equiv.
+ rewrite <- bt_cls_hfs_repr_iff, bt_cls_hfs_repr; tauto.
+ tauto.
Qed.
Opaque hfs_empty hfs_cons hfs_mem.
Theorem hfs_comprehension X (P : X -> Prop) (f : X -> hfs) :
fin_t P
-> { s | forall a, a ∈ s <-> exists x, P x /\ f x = a }.
Proof.
intros (l & Hl).
assert { s | forall a, a ∈ s <-> exists x, In x l /\ f x = a } as H.
{ exists (fold_right (fun x => hfs_cons (f x)) hfs_empty l).
clear Hl; intros a.
induction l as [ | x l IHl ]; simpl.
+ rewrite hfs_empty_spec; split; try tauto.
intros (? & [] & _).
+ rewrite hfs_cons_spec, IHl; split.
* intros [ -> | (y & ? & <-) ].
- exists x; auto.
- exists y; auto.
* intros (y & [ -> | ? ] & <-); auto.
right; exists y; auto. }
destruct H as (s & Hs).
exists s; intro a; rewrite Hs.
fol equiv; intro; rewrite Hl; tauto.
Qed.
Fact hfs_select t (P : hfs -> Prop) :
(forall x, x ∈ t -> { P x } + { ~ P x })
-> { s | forall x, x ∈ s <-> x ∈ t /\ P x }.
Proof.
intros H.
destruct btm_select with (P := fun x => P (cls x)) (t := repr t)
as (s & Hs).
+ intros x y E.
apply bt_cls_equiv in E.
rewrite E; auto.
+ intros x Hx.
apply H, btm_cls_repr; auto.
+ exists (bt_cls s); intros x.
rewrite btm_repr_cls, Hs, bt_cls_hfs_repr; tauto.
Qed.
Definition hfs_pow t := cls (bt_pow (repr t)).
Notation "x ⊆ y" := (forall u, u ∈ x -> u ∈ y).
Fact hfs_incl_refl r : r ⊆ r.
Proof. apply mb_incl_refl. Qed.
Fact hfs_incl_trans r s t : r ⊆ s -> s ⊆ t -> r ⊆ t.
Proof. apply mb_incl_trans. Qed.
Fact hfs_incl_ext s t : s = t <-> s ⊆ t /\ t ⊆ s.
Proof.
split.
+ intros []; auto.
+ rewrite hfs_mem_ext; intros []; split; auto.
Qed.
Fact hfs_pow_spec s x : x ∈ hfs_pow s <-> x ⊆ s.
Proof.
unfold hfs_pow.
rewrite btm_repr_cls, bt_pow_spec.
split.
+ intros H z Hz.
rewrite <- (bt_cls_hfs_repr z).
apply btm_cls_repr, H; auto.
+ intros H z.
specialize (H (cls z)).
do 2 rewrite btm_cls_repr in H; auto.
Qed.
Definition hfs_transitive t := forall u v, u ∈ v -> v ∈ t -> u ∈ t.
Fact bt_hfs_transitive t : hfs_transitive t <-> bt_transitive (repr t).
Proof.
split.
+ intros H u v G.
do 2 rewrite <- btm_cls_repr.
apply H.
rewrite btm_cls_repr, hfs_repr_bt_cls; auto.
+ intros H u v G.
do 2 rewrite hfs_mem_repr.
apply H; auto.
Qed.
Definition hfs_tc t := cls (bt_tc (repr t)).
Fact hfs_tc_trans t : hfs_transitive (hfs_tc t).
Proof.
intros u v; unfold hfs_tc.
do 2 rewrite btm_repr_cls.
rewrite hfs_mem_repr.
apply bt_tc_trans.
Qed.
Fact hfs_tc_incl t : t ⊆ hfs_tc t.
Proof.
unfold hfs_tc.
intros x Hx.
rewrite btm_repr_cls.
apply bt_tc_incr; auto.
Qed.
Fact hfs_pow_trans t : hfs_transitive t -> hfs_transitive (hfs_pow t).
Proof.
unfold hfs_pow; intros H u v.
do 2 rewrite btm_repr_cls.
rewrite hfs_mem_repr.
apply bt_pow_transitive.
apply bt_hfs_transitive; auto.
Qed.
Definition hfs_card n := cls (nat2bt n).
Fact hfs_card_transitive n : hfs_transitive (hfs_card n).
Proof.
unfold hfs_card.
apply bt_hfs_transitive.
intros ? ?.
rewrite hfs_repr_bt_cls.
apply nat2bt_transitive.
Qed.
Definition hfs_pos n (p : pos n) := cls (pos2bt p).
Fact hfs_pos_card n x : x ∈ hfs_card n <-> exists p, x = @hfs_pos n p.
Proof.
unfold hfs_pos, hfs_card.
rewrite btm_repr_cls; split.
+ intros Hx.
exists (bt2pos _ Hx).
symmetry; apply bt_cls_hfs_repr_iff.
rewrite bt2pos_fix; auto.
+ intros (p & ->).
rewrite hfs_repr_bt_cls.
apply pos2bt_in.
Qed.
Fact hfs_card_empty n : ∅ ∈ hfs_card (S n).
Proof.
apply hfs_pos_card.
exists pos0.
apply hfs_mem_ext.
intros x; rewrite hfs_empty_spec; split; simpl; try tauto.
unfold hfs_pos; rewrite btm_repr_cls.
unfold pos2bt; rewrite pos2nat_fst; simpl.
btm simpl.
Qed.
Fact hfs_pos_prop n p : @hfs_pos n p ∈ hfs_card n.
Proof.
apply hfs_pos_card; exists p; auto.
Qed.
Definition hfs_card_pos n x : x ∈ hfs_card n -> pos n.
Proof.
intros H.
apply btm_repr_cls in H.
apply (bt2pos _ H).
Defined.
Fact hfs_card_pos_spec n x Hx : x = hfs_pos (@hfs_card_pos n x Hx).
Proof.
unfold hfs_card_pos, hfs_pos.
symmetry; apply bt_cls_hfs_repr_iff.
rewrite bt2pos_fix; auto.
Qed.
Fact hfs_pos_inj n p q : @hfs_pos n p = hfs_pos q -> p = q.
Proof.
unfold hfs_pos.
rewrite bt_cls_equiv.
apply pos2bt_inj.
Qed.
Fact hfs_card_pos_pirr n x H1 H2 : @hfs_card_pos n x H1 = @hfs_card_pos n x H2.
Proof. apply hfs_pos_inj; do 2 rewrite <- hfs_card_pos_spec; auto. Qed.
Fact hfs_bij_t n : { t : hfs &
{ f : pos n -> hfs &
{ g : forall x, x ∈ t -> pos n |
hfs_transitive t
/\ (0 < n -> ∅ ∈ t)
/\ (forall p, f p ∈ t)
/\ (forall p H, g (f p) H = p)
/\ forall x H, f (g x H) = x } } }.
Proof.
exists (hfs_card n), (@hfs_pos _),
(@hfs_card_pos _); msplit 4.
+ apply hfs_card_transitive.
+ destruct n as [ | n ]; try lia; intros _; apply hfs_card_empty.
+ apply hfs_pos_prop.
+ intros p H; apply hfs_pos_inj; rewrite <- hfs_card_pos_spec; auto.
+ intros; rewrite <- hfs_card_pos_spec; auto.
Qed.
Theorem hfs_pos_n_transitive n :
{ l : hfs & { f : hfs -> pos (S n) &
{ g : pos (S n) -> hfs |
hfs_transitive l
/\ ∅ ∈ l
/\ (forall p, g p ∈ l)
/\ (forall x, x ∈ l -> exists p, x = g p)
/\ (forall p, f (g p) = p) } } }.
Proof.
destruct (hfs_bij_t (S n)) as (u & i & j & H1 & H0 & H2 & H3 & H4).
set (f x :=
match hfs_mem_dec x u with
| left H => @j _ H
| right _ => pos0
end).
exists u, f, i; msplit 4; auto.
+ apply H0; lia.
+ intros x Hx.
exists (j x Hx); rewrite H4; auto.
+ intros p; unfold f.
destruct (hfs_mem_dec (i p) u) as [ H | H ].
* rewrite H3; auto.
* destruct H; auto.
Qed.
Opaque hfs_pow.
Fact hfs_pow_trans_incr t : hfs_transitive t -> t ⊆ hfs_pow t.
Proof.
intros Ht z H; apply hfs_pow_spec.
intros u Hu; revert Hu H; apply Ht.
Qed.
Fact hfs_pow_mono s t : s ⊆ t -> hfs_pow s ⊆ hfs_pow t.
Proof.
intros H x; do 2 rewrite hfs_pow_spec.
intros G z Hz; apply H, G; auto.
Qed.
Fact hfs_iter_pow_mono s t n : s ⊆ t -> iter hfs_pow s n ⊆ iter hfs_pow t n.
Proof.
revert s t; induction n as [ | n IHn ]; simpl; intros s t Hst; auto.
apply IHn, hfs_pow_mono, Hst.
Qed.
Fact hfs_iter_pow_trans s n : hfs_transitive s -> hfs_transitive (iter hfs_pow s n).
Proof.
revert s; induction n as [ | n IHn ]; intros s Hs; simpl; auto.
apply IHn, hfs_pow_trans; auto.
Qed.
Fact hfs_iter_pow_le t n m : n <= m -> hfs_transitive t -> iter hfs_pow t n ⊆ iter hfs_pow t m.
Proof.
intros H; revert H t.
induction 1 as [ | m H IH ]; auto; intros t Ht.
apply hfs_incl_trans with (1 := IH _ Ht); simpl.
apply hfs_iter_pow_mono, hfs_pow_trans_incr, Ht.
Qed.
Opaque hfs_cons.
Definition hfs_pair (r s : hfs) : hfs := hfs_cons r (hfs_cons s hfs_empty).
Fact hfs_pair_spec r s x : x ∈ hfs_pair r s <-> x = r \/ x = s.
Proof.
unfold hfs_pair.
do 2 rewrite hfs_cons_spec.
rewrite hfs_empty_spec; tauto.
Qed.
Fact hfs_pair_spec' p r s : p = hfs_pair r s <-> (forall x, x ∈ p <-> x = r \/ x = s).
Proof.
rewrite hfs_mem_ext.
fol equiv; intro.
rewrite hfs_pair_spec; tauto.
Qed.
Opaque hfs_pair.
Fact hfs_pair_pow r s t : r ∈ t -> s ∈ t -> hfs_pair r s ∈ hfs_pow t.
Proof.
rewrite hfs_pow_spec.
intros H1 H2 x.
rewrite hfs_pair_spec.
intros [ -> | -> ]; auto.
Qed.
Fact hfs_pair_mem_l a b : a ∈ hfs_pair a b.
Proof. apply hfs_pair_spec; auto. Qed.
Fact hfs_pair_mem_r a b : b ∈ hfs_pair a b.
Proof. apply hfs_pair_spec; auto. Qed.
Fact hfs_pair_inj a b x y : hfs_pair a b = hfs_pair x y
-> a = x /\ b = y
\/ a = y /\ b = x.
Proof.
intros E.
generalize (hfs_pair_mem_l a b) (hfs_pair_mem_r a b)
(hfs_pair_mem_l x y) (hfs_pair_mem_r x y).
rewrite <- E, E at 1 2.
do 4 rewrite hfs_pair_spec.
do 4 intros [[]|[]]; auto.
Qed.
Definition hfs_opair r s := hfs_pair (hfs_pair r r) (hfs_pair r s).
Notation "⟬ x , y ⟭" := (hfs_opair x y).
Fact hfs_opair_pow r s t : r ∈ t -> s ∈ t -> hfs_opair r s ∈ iter hfs_pow t 2.
Proof. intros; do 2 apply hfs_pair_pow; auto. Qed.
Fact hfs_opair_inj a b x y : ⟬a,b⟭ = ⟬x,y⟭ -> a = x /\ b = y.
Proof.
unfold hfs_opair.
intros H.
apply hfs_pair_inj in H as [ (H1 & H2) | (H1 & H2) ];
apply hfs_pair_inj in H1; apply hfs_pair_inj in H2;
revert H1 H2;
do 2 intros [ [] | [] ]; subst; auto.
Qed.
Fact hfs_opair_spec a b x y : ⟬a,b⟭ = ⟬x,y⟭ <-> a = x /\ b = y.
Proof.
split.
+ apply hfs_opair_inj.
+ intros [ [] [] ]; auto.
Qed.
Fact hfs_opair_spec' p x y : p = ⟬x,y⟭ <-> exists a b, a = hfs_pair x x
/\ b = hfs_pair x y
/\ p = hfs_pair a b.
Proof.
unfold hfs_opair; split; eauto.
intros (? & ? & -> & -> & ->); auto.
Qed.
Fixpoint hfs_tuple n (v : vec hfs n) :=
match v with
| vec_nil => ∅
| x##v => ⟬x,hfs_tuple v⟭
end.
Fact hfs_tuple_pow n v t : ∅ ∈ t -> hfs_transitive t -> (forall p, vec_pos v p ∈ t) -> @hfs_tuple n v ∈ iter hfs_pow t (2*n).
Proof.
intros Ht1 Ht2.
induction v as [ | x n v IHv ]; intros Hv.
+ simpl; auto.
+ replace (2*S n) with (2*n+2) by lia; rewrite iter_plus.
simpl hfs_tuple; apply hfs_opair_pow.
* apply hfs_iter_pow_le with 0; try lia; auto.
simpl; apply (Hv pos0).
* apply IHv; auto.
intro; apply (Hv (pos_nxt _)).
Qed.
Fact hfs_tuple_spec n v w : @hfs_tuple n v = hfs_tuple w <-> v = w.
Proof.
split.
+ induction n as [ | n IHn ] in v, w |- *.
* vec nil v; vec nil w; auto.
* vec split v with x; vec split w with y; simpl.
rewrite hfs_opair_spec; intros (-> & H); f_equal; revert H; auto.
+ intros ->; auto.
Qed.
Variable (t : hfs) (Hp : hfs_transitive t).
Fact hfs_trans_pair_inv x y : hfs_pair x y ∈ t -> x ∈ t /\ y ∈ t.
Proof using Hp.
intros H; split; apply Hp with (2 := H); apply hfs_pair_spec; auto.
Qed.
Fact hfs_trans_opair_inv x y : ⟬x,y⟭ ∈ t -> hfs_pair x x ∈ t /\ hfs_pair x y ∈ t.
Proof using Hp. apply hfs_trans_pair_inv. Qed.
Fact hfs_trans_otriple_inv x y z : ⟬⟬x,y⟭,z⟭ ∈ t -> ⟬x,y⟭ ∈ t /\ z ∈ t.
Proof using Hp.
intros H.
apply hfs_trans_opair_inv, proj2, hfs_trans_pair_inv in H.
auto.
Qed.
Fact hfs_trans_tuple_inv n v : @hfs_tuple n v ∈ t -> forall p, vec_pos v p ∈ t.
Proof using Hp.
induction v as [ | n x v IHv ]; simpl hfs_tuple; intros H p; invert pos p;
apply hfs_trans_opair_inv, proj2, hfs_trans_pair_inv in H;
destruct H; auto.
Qed.
End hfs.