Require Import Arith Lia List.
From Undecidability.DiophantineConstraints Require Import H10C.

Set Default Proof Using "Type".


Section Utils.

  Lemma c2_full (x:) : {y: | x * S x = y+y}.
  Proof.
    induction x as [|x [y' IH]].
    - exists 0. .
    - exists (y'+x+1). nia.
  Qed.


  Definition (x:) := match (c2_full x) with exist _ y _ y end.

  Lemma c2_descr (x:) : x * S x = x + x.
  Proof.
    unfold . now destruct (c2_full x).
  Qed.


  Lemma h10upc_inv (a b c d : ) : h10upc_sem_direct ((a,S b),(c,d))
           {c': & {d': & h10upc_sem_direct ((a,b),(c',d'))
                                S c' = c d' + b + 1 = d}}.
  Proof.
  intros [Hl Hr].
  exists (a + S b). exists ( b).
  repeat split.
  - .
  - apply c2_descr.
  - .
  - enough (2*( b + b + 1) = d+d) by nia. rewrite Hr.
    cbn. rewrite Nat.mul_comm. cbn. symmetry.
    pose (c2_descr b) as Hb. nia.
  Qed.


  Lemma h10_rel_irref (p:*) : (h10upc_sem_direct (p,p)).
  Proof.
  intros H. destruct p as [a b]. cbn in H. .
  Qed.


  Definition highest_var (x:h10upc) := match x with ((a,b),(c,d)) Nat.max a (Nat.max b (Nat.max c d)) end.
  Lemma highest_var_descr (x:h10upc) : let hv := highest_var x in match x with ((a,b),(c,d)) a hv b hv c hv d hv end.
  Proof.
  destruct x as [[a b] [c d]]. cbn. repeat split; .
  Qed.


  Fixpoint highest_var_list (x:list h10upc) := match x with nil 0 | x::xr Nat.max (highest_var x) (highest_var_list xr) end.
  Lemma highest_var_list_descr (x:list h10upc) (h:h10upc) : In h x highest_var h highest_var_list x.
  Proof.
  induction x as [|hh x IH].
  - intros [].
  - intros [hhh|hx].
    + cbn. rewrite hhh. .
    + cbn. specialize (IH hx). .
  Qed.


  Fixpoint highest_num (env: ) (n:) : := match n with 0 env 0 | S n Nat.max (env (S n)) (highest_num env n) end.
  Lemma highest_num_descr (env: ) (n:) (m:) : m n env m highest_num env n.
  Proof.
  induction n as [|n IH].
  - intros Hm. assert (m=0) as . 1:. cbn. rewrite . .
  - intros HmSn. cbn. destruct (Nat.eq_dec (S n) m) as [Heq|Hneq].
    + rewrite Heq. .
    + assert (m n) as Hmn. 1:. specialize (IH Hmn). .
  Qed.


End Utils.

Section InductiveCharacterization.


  Definition (P : (*)*(*) Prop) := a c, P ((a,0),(c,0)) a + 1 = c.
  Definition (P : (*)*(*) Prop) := a b c d , (b 0 P ((a,b),(c,d)))
               ( b' c' d', P ((a,b'),(c',d')) P ((d',b'),(d,d')) P ((b',0),(b,0)) P ((c',0),(c,0))).
  Definition ax2w (P : (*)*(*) Prop) := a b c d ,
               ( b' c' d', P ((a,b'),(c',d')) P ((d',b'),(d,d')) P ((b',0),(b,0)) P ((c',0),(c,0)))
                (P ((a,b),(c,d))).
  Definition (P : (*)*(*) Prop) := a c d, P ((a,0),(c,d)) d = 0.

  Definition sat P := P P P.
  Definition satw P := P ax2w P.

  Inductive h10upc_ind : Prop :=
    base : a, h10upc_ind a 0 (S a) 0
  | step : a b c d b' c' d', h10upc_ind a b' c' d'
                                  h10upc_ind d' b' d d'
                                  h10upc_ind b' 0 b 0
                                  h10upc_ind c' 0 c 0
                                  h10upc_ind a b c d.

  Lemma h10upc_ind_not_less_0 : k, h10upc_ind k 0 0 0 False.
  Proof.
  enough ( a b c d, h10upc_ind a b c d b = 0 c = 0 d = 0 False) as H.
  1: intros k ; apply (H k 0 0 0 ); easy.
  intros a b c d H.
  unshelve eapply (h10upc_ind_ind
                   ( a b c d b = 0 c = 0 d = 0 False)
                   _ _ a b c d H); clear a b c d H.
  - intros a Hb Hc Hd. .
  - intros a b c d b' c' d' Hb Hc Hd; cbn in *; subst.
    apply ; easy.
  Qed.


  Lemma base_equiv a c d : h10upc_sem_direct ((a,0),(c,d)) h10upc_ind a 0 c d.
  Proof. split.
  * intros [ ]. assert (d=0) as by . assert (c = S a) as by . apply base.
  * intros H. inversion H as [a' |a' b' c' d' b'' c'' d'' ].
    - cbn. .
    - exfalso. now eapply h10upc_ind_not_less_0 with b''.
  Qed.


  Lemma h10_equiv a b c d : h10upc_sem_direct ((a,b),(c,d)) h10upc_ind a b c d.
  Proof. induction b as [|b IH] in a,c,d|-*.
  - apply base_equiv.
  - symmetry. split.
    * intros H. inversion H; subst.
      rewrite base_equiv in , . cbn in ,.
      assert (b' = b) as by .
      assert (S c' = c) as by .
      rewrite IH in ,. cbn in ,. cbn. .
    * intros [ ]. eapply step with b (c-1) (d-b-1).
      + rewrite IH. cbn; .
      + rewrite IH. cbn; .
      + rewrite base_equiv. cbn; .
      + rewrite base_equiv. cbn; .
  Qed.


  Lemma eqRelSat : sat h10upc_sem_direct.
  Proof.
  split. 2:split.
  - intros a c. cbn. .
  - intros a. intros. split.
    * intros [ [ ]]. destruct b as [|b']. 1:easy.
      exists b', (c-1), (d-b'-1). repeat split.
      all: .
    * intros [b' [c' [d' [ [ [ ]]]]]]. cbn in ,,,. cbn; .
  - intros a c d. cbn. .
  Qed.


  Lemma satEquiv0 P Q : sat P satw Q a c d, P ((a,0),(c,d)) Q ((a,0),(c,d)).
  Proof. intros [ [ ]] [ ] a c d.
  intros H.
  * pose proof ( a c d H) as k. rewrite k in *.
    rewrite ( a c) in H. rewrite ( a c). easy.
  Qed.


  Lemma satEquiv P Q : sat P satw Q a b c d, P ((a,b),(c,d)) Q ((a,b),(c,d)).
  Proof. intros [ [ ]] [ ] a b c d.
  induction b as [|b' IH] in a,c,d|-*.
  * apply satEquiv0; firstorder.
  * destruct ( a (S b') c d) as [ ].
    pose proof ( a (S b') c d) as .
    intros H.
    - apply . destruct as [b'' [c' [d' [ [ [ ]]]]]].
      + split; easy.
      + exists b'', c', d'. unfold in . rewrite in . assert (b'' = b') as by .
        unfold in . rewrite !. rewrite !. rewrite in . split. 2:split. 3:tauto.
        all: apply IH; easy.
  Qed.


  Lemma satCongr P Q : ( a b c d, P ((a,b),(c,d)) Q ((a,b),(c,d))) sat P sat Q.
  Proof.
  intros H [ [ ]]. split. 2:split.
  - unfold in *. intros a c. rewrite H. apply .
  - unfold in *. intros a b c d. rewrite H. split.
    * destruct ( a b c d) as [ _]. intros .
      destruct ( ) as [b' [c' [d' ]]].
      exists b', c', d'. rewrite !H. apply .
    * destruct ( a b c d) as [_ ]. intros [b' [c' [d' ]]].
      apply . exists b',c',d'. rewrite !H. apply .
  - unfold in *. intros a c d. rewrite H. apply .
  Qed.


  Definition h10upc_ind' '((a,b),(c,d)) := h10upc_ind a b c d.

  Lemma indRelSat : sat h10upc_ind'.
  Proof.
  eapply satCongr with h10upc_sem_direct.
  - intros a b c d. apply h10_equiv.
  - apply eqRelSat.
  Qed.


  Lemma sat_satw P : sat P satw P.
  Proof.
  intros [ [ ]]. split.
  * easy.
  * intros a b c d H. destruct ( a b c d) as [_ H2R]. now apply H2R.
  Qed.


End InductiveCharacterization.