(* First property of uniform interpolation *)

Require Import List.
Export ListNotations.
Require Import PeanoNat Arith.
Require Import Lia.
Require Import String.

Require Import general_export.

Require Import KS_export.

Require Import UIK_Def_measure.
Require Import UIK_Canopy.
Require Import UIK_irred_short.
Require Import UIK_braga.
Require Import UIK_UI_prelims.

  Section UIPOne.

  (* The formula defined by the function UI satisfies all the properties of
      uniform interpolation. *)


  Theorem UI_One : forall s p q, In (# q) (propvar_subform (UI p (fst s, snd s))) ->
                                                      ((q <> p) * (In (# q) (propvar_subform_list (fst s ++ snd s)))).
  Proof.
  intro s. remember (measure s) as n. revert Heqn. revert s. revert n.
  induction n as [n IH] using (well_founded_induction_type lt_wf).
  intros s Heqn p q H0. rewrite propvar_subform_list_app.
  destruct (empty_seq_dec s).
  (* s is the empty sequent. *)
  { subst ; simpl in *. assert (H : GUI p ([],[]) Bot) by (apply GUI_empty_seq ; auto). apply UI_GUI in H.
    rewrite H in *. simpl in H0. inversion H0. }
  (* s is not the empty sequent. *)
  { destruct (critical_Seq_dec s).
  (* s is a critical sequent *)
  - destruct (dec_KS_init_rules s).
    (* s is an initial sequent *)
    + assert (is_init s) ; auto.
       assert (H1 : GUI p s Top) by (apply GUI_critic_init ; auto). apply UI_GUI in H1.
       destruct s. simpl in H0. rewrite H1 in H0. simpl in H0. inversion H0.
    (* s is not an initial sequent *)
    + remember (fst s) as LHS.
       assert (H1 : GUI p s
       (Or (list_disj (restr_list_prop p (snd s)))
       (Or (list_disj (map Neg (restr_list_prop p (fst s))))
       (Or (list_disj (map Box (map (UI p) (KR_prems s))))
       (Diam (UI p (unboxed_list (top_boxes (fst s)), []%list))))))).
       apply GUI_critic_not_init ; auto. apply Gimap_map ; intros. 1-2: apply UI_GUI ; auto.
       destruct s. simpl in *. apply UI_GUI in H1. simpl in HeqLHS. subst. rewrite H1 in H0. simpl in H0.
       repeat rewrite app_nil_r in H0. clear H1.
       apply in_app_or in H0. destruct H0 as [H0 | H0].

       apply propvar_subform_list_disj in H0.
       apply propvar_subform_list_restr_list_prop in H0. destruct H0 ; split ; auto. apply in_or_app ; auto.

       apply in_app_or in H0 ; destruct H0 as [H0 | H0]. apply propvar_subform_list_disj in H0. apply propvar_subform_list_witness in H0.
       destruct H0. destruct H. apply in_map_iff in H. destruct H. destruct H ; subst. simpl in H0.
       rewrite app_nil_r in H0. unfold restr_list_prop in H1. apply in_remove in H1. destruct H1.
       pose (In_list_prop_LF _ _ H). destruct p0. destruct s. subst. simpl in H0. destruct H0. inversion H0. subst.
       destruct (string_dec q p). exfalso ; apply H1 ; subst ; auto. split ; auto. apply in_or_app ; left.
       apply list_prop_LF_propvar_subform_list in H ; auto. inversion H0.

       apply in_app_or in H0 ; destruct H0. apply propvar_subform_list_disj in H. apply propvar_subform_list_witness in H.
       destruct H. destruct H. apply in_map_iff in H. destruct H. destruct H ; subst. simpl in H0.
       apply in_map_iff in H1. destruct H1. destruct H ; subst. assert (In # q (propvar_subform (UI p (fst x, snd x)))).
       destruct x ; auto.
       unfold KR_prems in H1. destruct (finite_KR_premises_of_S (l, l0)). simpl in H1.
       apply In_InT_seqs in H1. apply InT_flatten_list_InT_elem in H1. destruct H1. destruct p1.
       apply p0 in i0. inversion i0 ; subst. inversion i ; subst. 2: inversion X0. simpl in H. repeat rewrite propvar_subform_list_app.
       simpl ; repeat rewrite propvar_subform_list_app.
       assert (J0: measure (unboxed_list , [A]) < measure (l, Δ0 ++ Box A :: Δ1)).
       unfold measure. simpl. repeat rewrite size_LF_dist_app. simpl.
       pose (size_nobox_gen_ext _ _ X). simpl in l.
       pose (size_unboxed ). lia.
       assert (J1: measure (unboxed_list , [A]) = measure (unboxed_list , [A])). auto.
       pose (IH _ J0 _ J1 _ _ H0). destruct p1. split ; auto. simpl in i1.
       rewrite propvar_subform_list_app in i1. apply in_app_or in i1. destruct i1.
       apply in_or_app ; left. apply propvar_subform_list_unboxed_list in H1.
       pose (propvar_subform_list_nobox_gen_ext _ _ X). simpl in i1. apply i1 ; auto.
       simpl in H1. rewrite app_nil_r in H1.
       apply in_or_app ; right ; apply in_or_app ; right ; apply in_or_app ; auto.

       destruct l ; subst ; simpl in *.
       { assert (GUI p ([],[]) Bot). apply GUI_empty_seq ; auto. apply UI_GUI in H0.
         rewrite H0 in *. simpl in H. inversion H. }
       { assert (J0: measure (unboxed_list (top_boxes (m :: l)), []%list) < measure (m :: l, l0)).
         unfold measure. simpl. destruct m ; simpl.
         1-4: pose (size_unboxed (top_boxes l)) ; pose (size_top_boxes l) ; lia.
         assert (J1: measure (unboxed_list (top_boxes (m :: l)), []%list) = measure (unboxed_list (top_boxes (m :: l)), []%list)). auto.
         pose (IH _ J0 _ J1). simpl in p0. pose (p0 _ _ H). destruct p1. split ; auto. simpl in i. clear p0.
         rewrite propvar_subform_list_app in i. apply in_app_or in i. destruct i.
         apply in_or_app ; left. apply propvar_subform_list_unboxed_list in H0.
         apply in_or_app. destruct m ; simpl in H0 ; auto.
         1-3: right ; apply propvar_subform_list_top_boxes ; auto. simpl.
         apply in_app_or in H0 ; destruct H0 ; auto. right. apply propvar_subform_list_top_boxes ; auto.
         simpl in H0. inversion H0. }
  (* s is not a critical sequent *)
  - assert (H1 : GUI p s (list_conj (map (UI p) (Canopy s)))). apply GUI_not_critic ; auto.
    apply Gimap_map ; intros ; apply UI_GUI ; auto. apply UI_GUI in H1. destruct s.
    simpl in H0. rewrite H1 in H0. apply propvar_subform_list_conj in H0.
    apply propvar_subform_list_witness in H0. destruct H0 as [s [H0 H3]].
    apply in_map_iff in H0.
    destruct H0 as [x0 H0]. destruct H0 as [H0 Hc]; subst. simpl.
    assert (H2 : In # q (propvar_subform (UI p (fst x0, snd x0)))) by (destruct x0 ; auto).
    pose (i := In_InT_seqs _ _ Hc). apply Canopy_measure in i. destruct i ; subst.
    simpl in *. exfalso. apply f. apply In_InT_seqs in Hc ; apply Canopy_critical in Hc ; auto.
    assert (measure x0 = measure x0) ; auto.
    pose (IH _ l1 _ H _ _ H2). destruct p0 ; split ; auto.
    apply propvar_subform_list_Canopy with (A:=# q) in Hc ; auto.
    simpl in H3 ; rewrite propvar_subform_list_app in Hc ; auto. }
  Qed.

  End UIPOne.