Require Import Vector.
From Undecidability.DiophantineConstraints Require Import H10C Util.H10UPC_facts.
From Undecidability.FOL Require Semantics.FiniteTarski.Fragment.
From Undecidability.FOL Require Import Syntax.Facts Deduction.FullNDFacts
                Semantics.Tarski.FullSoundness Semantics.Tarski.FullFacts Syntax.BinSig
                Semantics.FiniteTarski.Full.
From Undecidability.Shared Require Import Dec.
From Undecidability.Shared.Libs.PSL Require Import Numbers.
From Undecidability.Shared.Libs.DLW.Wf Require Import wf_finite.
From Coq Require Import Arith Lia List.

From Undecidability.FOL.Semantics.FiniteTarski Require Import Full DoubleNegation.
From Undecidability.Synthetic Require Import Definitions DecidabilityFacts.
Require Import Undecidability.Synthetic.Definitions Undecidability.Synthetic.Undecidability.
Require Import Datatypes.
Require Import Relation_Definitions.
Require Import Setoid.
Require Import Relation_Definitions.


Set Default Proof Using "Type".
Set Default Goal Selector "!".
Set Mangle Names.


#[local] Existing Instance sig_empty.
#[local] Existing Instance sig_binary.
#[local] Existing Instance full_operators.

Import FullSyntax.

Notation "t ## t'" := (@atom _ sig_binary _ _ tt (Vector.cons _ t _ (Vector.cons _ t' _ (Vector.nil _)))) (at level 30).
Definition Pr t t' := t ## t'.

Section Utils.
  Definition proj_vec2 D : t D 2 D*D.
  Proof.
    intros k. refine (match k with @Vector.nil _ _ | @Vector.cons _ x n xr _ end). 1:easy.
    destruct n as [|[|n]]. 1,3:easy.
    refine (match xr with @Vector.nil _ _ | @Vector.cons _ y n yr _ end). 1:easy.
    destruct n as [|n]. 2:easy.
    exact (x,y).
  Defined.


  Lemma proj_vec2_correct D x y v : proj_vec2 v = (x,y) v = Vector.cons D x 1 (Vector.cons D y 0 (Vector.nil D)).
  Proof.
  split.
  - refine (match v with @Vector.nil _ _ | @Vector.cons _ x' n xr _ end). 1:easy.
    destruct n as [|[|n]]. 1,3:easy.
    refine (match xr with @Vector.nil _ _ | @Vector.cons _ y' n yr _ end). 1:easy.
    destruct n as [|n]. 2:easy. cbn. intros H. f_equal. 2:f_equal. 1-2:congruence.
    refine (match yr with @Vector.nil _ _ end).
    easy.
  - intros . easy.
  Qed.


  Lemma it_shift (X:Type) (f:XX) v n : it f (S n) v = it f n (f v).
  Proof.
  induction n as [|n IH].
  - easy.
  - cbn. f_equal. apply IH.
  Qed.


End Utils.

Section Fsat.
  Import FullSyntax.
  Context {h10 : list h10upc}.
  Definition N a := $a ## $a.
  Definition leq a b := N a N b $a ## $b.
  Definition P' a := ¬ N a.
  Definition P p a b := P' p N a N b $a ## $p $p ## $b.
  Definition deq a b := ($0 ## $(S a) $0 ## $(S b)) ( $(S a) ## $0 $(S b) ## $0).
  Definition less a b := leq a b ¬ (deq a b).
  Definition rel a b c d := ∃∃ P 1 (2+a) (2+b) P 0 (2+c) (2+d) $1 ## $0.
  Definition succ l r z := rel l z r z.

  Definition aTrans := ∀∀∀ less 2 1 less 1 0 less 2 0.
  Definition aPred z:= N 0 (¬(deq (S z) 0) succ 0 1 (2+z)).
  Definition aSucc z:= ∀∀ N 1 N 0 rel 1 (2+z) 0 (2+z)
                        less 1 0 less 0 1 leq 0 2.
  Definition aDescr z := ∀∀∀∀ N 3 N 2 N 1 N 0
                            (¬(deq (4+z) 2))
                            rel 3 2 1 0
                        ∃∃∃ succ 2 5 (7+z) succ 1 4 (7+z) rel 0 2 3 0 rel 6 2 1 0 less 0 3.
  Definition z := ∀∀∀∀ N 3 N 2 N 1 N 0 rel 3 2 1 0 deq 2 (4+z) deq 0 (4+z).
  Definition emplace_exists (n:) (f:form) := it ( k k) n f.
  Definition translate_single (h:h10upc) m := match h with
     ((a,b),(c,d)) rel a b c d
                     leq a m leq b m leq c m leq d m
  end.
  Fixpoint translate_list m (h10:list h10upc) := match with
     nil
   | x::xr translate_single x m translate_list m xr
  end.
  Definition F := ∃∃
    aTrans aPred 1 aSucc 1 aDescr 1 1
    emplace_exists (S (highest_var_list ))
    (translate_list (S (highest_var_list )) ).

  Section closedness.

    Lemma emplace_exists_bounded n phi k : bounded (k+n) bounded n (emplace_exists k ).
    Proof.
      induction k as [|k IH] in n,|-*; intros Hb.
      - easy.
      - cbn. eapply bounded_quant. apply IH. now rewrite Nat.add_succ_r.
    Qed.


    Lemma F_closed n : bounded n F.
    Proof.
      solve_bounds.
      apply emplace_exists_bounded.
      assert ( k, k highest_var_list
        bounded (k + S (S (S n))) (translate_list (S k) )) as Hk.
      2: apply Hk; .
      intros k Hk.
      induction as [|((xa &xb)& xc & xd) h10l IH] in Hk|-*.
      - cbn. solve_bounds.
      - cbn. cbn in Hk. solve_bounds.
        apply IH. .
    Qed.

  End closedness.

  Section inverseTransport.
    Context (D:Type).
    Context (I:interp D).
    Context (rho : env D).
    Context (decP : a b, dec ((a .: b.: ) Pr $0 $1)).
    Context (fini : cListable D).

    Notation iPr t t' := (@i_atom sig_empty sig_binary D _ tt (Vector.cons _ t _ (Vector.cons _ t' _ (Vector.nil _)))).
    Notation "a # b" := (iPr a b) (at level 50).
    Definition iN a := a # a.
    Definition ileq a b := iN a iN b a # b.
    Definition iP' a := iN a.
    Definition iP p a b := iP' p iN a iN b a # p p # b.
    Definition ideq a b := x, (x # a x # b) ( a # x b # x).
    Definition iless a b := ileq a b (ideq a b).
    Definition irel a b c d := pl pr, iP pl a b iP pr c d pl # pr.
    Definition isucc l r z := irel l z r z.

    Lemma to_N e i : e N i = iN (e i). Proof. easy. Qed.
    Lemma to_leq e a b : e leq a b ileq (e a) (e b). Proof. clear fini. cbn. unfold ileq,iN. tauto. Qed.
    Lemma to_P' e i : e P' i iP' (e i). Proof. clear fini. reflexivity. Qed.
    Lemma to_P e p a b : e P p a b iP (e p) (e a) (e b). Proof. clear fini. cbv. tauto. Qed.
    Lemma to_deq e a b : e deq a b ideq (e a) (e b). Proof. clear fini. cbv;tauto. Qed.
    Lemma to_less e a b : e less a b iless (e a) (e b). Proof. clear fini. cbv;tauto. Qed.
    Lemma to_rel e a b c d : e rel a b c d irel (e a) (e b) (e c) (e d). Proof. clear fini.
    split.
    - intros [p [q [[Hp Hq] Hpq]]]. exists p,q. firstorder.
    - intros [p [q [Hp [Hq Hpr]]]]. exists p,q. firstorder.
    Qed.

    Lemma to_succ e a b z : e succ a b z isucc (e a) (e b) (e z). Proof.
    clear fini. unfold succ, isucc. now rewrite to_rel. Qed.


    Notation "a == b" := (ideq a b) (at level 51).
    Notation "a << b" := (iless a b) (at level 51).
    Notation "a <<= b" := (ileq a b) (at level 52).
    Instance decPr (d1 d2 :D) : dec (iPr ).
    Proof using decP. apply decP. Defined.

    Instance eqDec (d1 d2 : D) : dec ( == ).
    Proof using fini decP.
    apply fin_dec. 1: apply fini.
    intros k. apply and_dec; apply and_dec; apply impl_dec; apply decPr.
    Defined.


    Lemma dEqRefl (d:D) : d == d.
    Proof. cbn. clear fini. cbv;tauto. Qed.
    Lemma dEqSymm (d1 d2:D) : == == .
    Proof. cbn. clear fini. firstorder. Qed.
    Lemma dEqTrans (d1 d2 d3:D) : == == == .
    Proof. cbn. clear fini. intros d; split; split; specialize ( d); specialize ( d); tauto. Qed.

    Add Parametric Relation : D ideq
      reflexivity proved by dEqRefl
      symmetry proved by dEqSymm
      transitivity proved by dEqTrans
    as eq_rel.

    Lemma rewrite_iPr (a b a' b' : D) : iPr a b a==a' b==b' iPr a' b'.
    Proof. clear fini. firstorder. Qed.

    Add Parametric Morphism : ileq
      with signature ideq ideq iff as leq_morph.
    Proof. cbn. clear fini. firstorder. Qed.
    Add Parametric Morphism : iless
      with signature ideq ideq iff as less_morph.
    Proof. intros . split; intros [Hl Hr]; clear fini; split.
    - rewrite , . firstorder.
    - intros Hc. apply Hr. now rewrite ,.
    - rewrite , ; firstorder.
    - intros Hc. apply Hr. now rewrite ,.
    Qed.

    Add Parametric Morphism : iN
      with signature ideq iff as N_morph.
    Proof. intros H. clear fini. firstorder. Qed.


    Opaque iN.
    Lemma helper_iP (a b c a' b' c':D) : iP a b c a==a'b==b'c==c' iP a' b' c'.
    Proof. intros [Hpa [Hnb [Hnc [Hpl Hpr]]]] Ha Hb Hc. cbn in Hpa,Hnb,Hnc,Hpl,Hpr. split. 2:split. 3:split. 4:split.
    - intros Hcc. apply Hpa. cbn in Hcc. now rewrite Ha.
    - now rewrite Hb.
    - now rewrite Hc.
    - now apply (rewrite_iPr Hpl).
    - now apply (rewrite_iPr Hpr).
    Qed.


    Add Parametric Morphism : iP
       with signature ideq ideq ideq iff as P_morph.
    Proof.
    intros a a' Ha b b' Hb c c' Hc. split; intros H; apply (helper_iP H). all: easy.
    Qed.


    Add Parametric Morphism : irel
       with signature ideq ideq ideq ideq iff as rel_morph.
    Proof.
    intros a a' Ha b b' Hb c c' Hc d d' Hd. split; intros [pl [pr [Hl [Hr Hlr]]]]; exists pl,pr; cbn in Hl,Hr; (split; [|split]).
    - now rewrite Ha, Hb.
    - now rewrite Hc, Hd.
    - easy.
    - now rewrite Ha, Hb.
    - now rewrite Hc, Hd.
    - easy.
    Qed.


    Add Parametric Morphism : isucc
      with signature ideq ideq ideq iff as succ_morph.
    Proof.
    intros l l' Hl r r' Hr z z' Hz. unfold isucc. now rewrite Hl,Hr,Hz.
    Qed.


    Lemma leq_eq a b : iN b a == b a b.
    Proof.
    intros H . now repeat split.
    Qed.


    Opaque N leq P' P deq less rel succ.

    Section withAxioms.

      Context {m z : D}.
      Context {rho' : env D}.
      Context {Hrho : = (m.:z.:)}.
      Context {vTrans : aTrans}.
      Context {vPred : aPred 1}.
      Context {vSucc : aSucc 1}.
      Context {vDescr : aDescr 1}.
      Context {vDescr2: 1}.

      Definition vpTrans a b c : a b b c a c.
      Proof using vTrans .
      intros Ha Hb. specialize (@vTrans a b c). fold sat in vTrans. cbn in vTrans.
      rewrite ! to_less in vTrans. cbn in vTrans. now apply vTrans.
      Qed.


      Definition vpPred x : iN x ~(x == z) p, isucc p x z.
      Proof using vPred m Hrho.
      intros Nx Hxz. specialize (@vPred x). fold sat in vPred. cbn in vPred. destruct vPred as [d Hd].
      - now rewrite to_N.
      - rewrite to_deq. cbn. rewrite Hrho. cbn. intros H. apply Hxz. now rewrite H.
      - exists d. rewrite to_succ in Hd. cbn in Hd. rewrite Hrho in Hd. cbn in Hd. easy.
      Qed.


      Definition vpSucc l r : isucc l r z (l r) k, k r k l.
      Proof using vSucc m Hrho.
      intros Hsucc. specialize (@vSucc l r). fold sat in vSucc. cbn in vSucc.
      rewrite ! to_N, to_rel, to_less in vSucc. cbn in vSucc.
      destruct vSucc as [Hl Hr]. 1-2:destruct Hsucc as [p [q [ [ ]]]]; firstorder. 1:rewrite Hrho; exact Hsucc. split.
      * easy.
      * intros k Hk. specialize (@Hr k). rewrite to_less, to_leq in Hr. cbn in Hr. now apply Hr.
      Qed.


      Ltac firstorder' := clear vTrans vPred vSucc fini; firstorder.
      Ltac recsplit n := let rec f n := match n with 0 idtac | S ?nn split; [idtac|f nn] end in f n.

      Add Parametric Relation : D iless
        transitivity proved by vpTrans
      as less_rel.

      Lemma less_irref (x : D) : (iless x x).
      Proof.
      intros [ ]. apply . firstorder'.
      Qed.

      Lemma less_wf : well_founded iless.
      Proof using fini vTrans.
      destruct fini as [l Hl]. apply wf_strict_order_list with l.
      - apply less_irref.
      - intros a b c Hab Hbc. eapply vpTrans. all: eassumption.
      - intros x y H. now apply Hl.
      Qed.


      Lemma less_leq a b c : a b b c a c.
      Proof using vTrans fini decP.
      intros . destruct (eqDec b c) as [Heq|Hneq].
      - now rewrite ! Heq in *.
      - transitivity b. 1:easy. now split.
      Qed.


      Lemma leq_less a b c : a b b c a c.
      Proof using vTrans fini decP.
      intros . destruct (eqDec a b) as [Heq|Hneq].
      - now rewrite ! Heq in *.
      - transitivity b. 2:easy. now split.
      Qed.


      Lemma leq_trans a b c : a b b c a c.
      Proof using vTrans fini decP.
      destruct (eqDec a b) as [|].
      - easy.
      - intros . enough (a c) as H by apply H.
        now eapply less_leq with b.
      Qed.


      Lemma aZeroS k : (k z).
      Proof using vTrans vSucc vPred m fini decP Hrho.
      induction k as [k IH] using (well_founded_ind less_wf).
      intros [ ]. destruct (@vpPred k) as [k' [ ]%vpSucc]. 1-2:firstorder.
      eapply (IH k'). 1:easy. eapply less_leq. 1:exact . easy.
      Qed.


      Lemma aZero2 k : iN k z k.
      Proof using vTrans vSucc vPred m fini decP Hrho.
      induction k as [k IH] using (well_founded_ind less_wf).
      intros Nk. destruct (eqDec z k) as [Heq|Hneq].
      - now apply leq_eq.
      - destruct (@vpPred k) as [k' [ ]%vpSucc]. 1:easy. 1: { intros Hc; contradict Hneq. now symmetry. }
        eapply leq_less with k'. 2:easy.
        apply IH. 2:firstorder'. easy.
      Qed.


      Lemma antiSym (a b : D) : a b b a a == b.
      Proof using vTrans fini decP.
      intros Ha Hb. destruct (eqDec a b) as [t|Hf]. 1:easy.
      assert (a a) as Hc.
      - eapply leq_less with b. 1:easy. split. 1:easy. intros H. apply Hf. now rewrite H.
      - exfalso. destruct Hc. firstorder'.
      Qed.


      Lemma eqDec_eq d1 d2 T (X Y : T) : == (if eqDec then X else Y) = X.
      Proof. intros H.
      destruct (eqDec ) as [Ht|Hf].
      - easy.
      - exfalso;easy.
      Qed.


      Definition chain (m:D) (mN:) (f:Doption ) :=
          ( d, d m f d None)
       ( n, ( d, d m f d = Some n) n mN)
       (f m = Some mN)
       (f z = Some 0)
       ( dl dh l h, f dl = Some l f dh = Some h S l = h isucc dl dh z)
       ( d1 d2, f None f = f == ).

      Lemma mkchain (d:D) : iN d n f, chain d n f.
      Proof using vTrans vSucc vPred m fini decP Hrho.
      induction d as [dd IH] using (well_founded_ind less_wf).
      intros H. destruct (eqDec dd z) as [|HS].
      - exists 0, ( k if eqDec k dd then Some 0 else None).
        recsplit 5.
        + intros d. split.
          * intros dl. destruct (eqDec d dd) as [Ht|Hf]. 1:easy.
            intros _. eapply aZeroS with d. split. 1: now rewrite . intros HH; apply Hf. transitivity z. 1:easy. now symmetry.
          * destruct (eqDec d dd) as [Hl|Hr]. 2: easy. intros _. apply leq_eq. all: easy.
        + intros n.
          intros [d [ddd Hdd]]. destruct (eqDec d dd). 1: assert (n=0) by congruence;. easy.
        + rewrite eqDec_eq; easy.
        + rewrite eqDec_eq. 1:easy. now symmetry.
        + intros dl dh l h ; split; intros ; destruct (eqDec dl dd), (eqDec dh dd). 1-4: congruence.
          all: destruct (vpSucc ) as [[ ] ]; exfalso; apply ; transitivity dd; [easy|now symmetry].
        + intros . intros . split; intros ; destruct (eqDec dd), (eqDec dd) as [Ht|Hf]. 2-5,7-8:easy.
          -- intros. transitivity dd; [easy|now symmetry].
          -- exfalso. apply Hf. transitivity ; [now symmetry|easy].
      - destruct (@vpPred dd) as [p Hp]. 1-2:firstorder'. destruct (vpSucc Hp) as [Hless Hclose].
        destruct (IH p) as [n [f Hnf]]. 1-2: firstorder'.
        exists (S n). exists ( v if eqDec v dd then Some (S n) else f v).
        destruct Hnf as [ [ [ [ [ ]]]]].
        recsplit 5.
        + intros d. split.
          * intros Hdd. destruct (eqDec d dd) as [Heq|Neq].
            -- easy.
            -- apply , Hclose. now split.
          * destruct (eqDec d dd) as [Heq|Neq].
            -- intros; now apply leq_eq.
            -- intros HN. eapply leq_trans with p.
              ++ rewrite in HN. easy.
              ++ apply Hless.
        + intros .
          intros [d [Hddd HSome]]. destruct (eqDec d dd). 1: assert (S n = ) by congruence;.
          enough ( n) by . apply ( ). exists d. split. 2:easy. apply Hclose. easy.
        + rewrite (eqDec_eq). 1:easy. firstorder'.
        + destruct (eqDec z dd) as [|]. 2: apply . exfalso. apply HS. now symmetry.
        + intros dl dh l h ; split; intros ; destruct (eqDec dl dd) as [|], (eqDec dh dd) as [|].
          * exfalso. assert (S l = l) by congruence. .
          * assert (h = S (S n)) as Hc by congruence. enough (h n) by . apply . exists dh. split. 2:easy. apply . intros Hh; congruence.
          * assert (l = n) as Hc by congruence. rewrite . enough (dl == p) as by easy.
            apply ; congruence.
          * apply with l h; easy.
          * destruct (vpSucc ) as [[ ] ]; exfalso; apply . now rewrite in .
          * exfalso. apply less_irref with dd. eapply vpTrans with dh.
            -- rewrite . now destruct (vpSucc ).
            -- eapply leq_less with p. 2:easy. rewrite . congruence.
          * rewrite in .
            assert (dl == p) as Hdlp.
            -- apply antiSym.
               ++ apply Hclose. destruct (vpSucc ) as [ ]. apply .
               ++ destruct (vpSucc ) as [[ ] ]. apply . easy.
            -- assert (f p = f dl) as Heq.
               ++ apply . 1:congruence. now symmetry.
               ++ assert (n = l) by congruence. subst n. congruence.
          * erewrite . 1:exact . all:easy.
        + intros . intros HSome. split; intros Heq; destruct (eqDec dd) as [Htt|Hff], (eqDec dd) as [Ht|Hf].
          -- now rewrite Htt,Ht.
          -- exfalso. enough (S n n) by . apply . exists . split. 2:easy. apply . now rewrite Heq.
          -- exfalso. enough (S n n) by . apply . exists . split. 2:easy. apply . now rewrite Heq.
          -- now apply .
          -- easy.
          -- exfalso. apply Hf. rewrite Htt. now symmetry.
          -- exfalso. apply Hff. now rewrite Heq.
          -- apply ; easy.
      Qed.


      Lemma chain_proves (a b c d: D) (nm : ) (f:Doption ): chain m nm f b m irel a b c d
                    a m c m d m
                    a' b' c' d', h10upc_sem_direct ((a',b'),(c',d'))
                         f a = Some a' f b = Some b' f c = Some c' f d = Some d'.
      Proof using vTrans vSucc vDescr fini decP Hrho.
      intros Hf. pose Hf as HHf. destruct HHf as [ [_ [_ [ [ ]]]]].
      induction b as [b IH] in a,c,d|-* using (well_founded_ind less_wf); intros Hb Habcd Ha Hc Hd.
      destruct (eqDec b z) as [Hbz|Hnbz].
      - destruct (f a) as [na|] eqn:Heqfa. 2: exfalso; apply ( a); easy.
        exists na, 0, (S na), 0. assert (d == z) as . 2: recsplit 4. 2:easy.
        + specialize (@ a b c d). fold sat in . cbn in .
          rewrite ! to_N, to_rel, ! to_deq, Hrho in . cbn in .
          apply . 1-4:firstorder'. all:easy.
        + easy.
        + rewrite . apply . 1: now apply . easy.
        + assert (isucc a c z) as Hsucc.
          * unfold isucc. rewrite Hbz at 1. now rewrite .
          * destruct (f c) as [Sna|] eqn:Hfc.
            -- f_equal. symmetry. erewrite ( a c); easy.
            -- exfalso. contradict Hfc. rewrite . easy.
        + symmetry. rewrite , . 2:congruence. now symmetry.
      - specialize (@vDescr a b c d). fold sat in vDescr. cbn in vDescr.
        setoid_rewrite Hrho in vDescr. cbn in vDescr.
        setoid_rewrite to_N in vDescr. cbn in vDescr.
        setoid_rewrite to_rel in vDescr. cbn in vDescr.
        setoid_rewrite to_deq in vDescr. cbn in vDescr.
        setoid_rewrite to_less in vDescr. cbn in vDescr.
        destruct vDescr as [b' [c' [d' [[[[Hb' Hc'] ] ] ]]]]. 1-4,6:firstorder'. 1: intros H; rewrite H in Hnbz; firstorder'.
        destruct (vpSucc Hb') as [ ].
        destruct (vpSucc Hc') as [ ].
        edestruct (IH b' (ltac:(firstorder')) d' d d') as [nd' [nb' [nd [ [ [Hnd' [ [ ]]]]]]]].
        2:easy. 3:easy. 2: apply leq_trans with d; firstorder. 1: eapply leq_trans with b; firstorder. 1: eapply leq_trans with d; firstorder.
        edestruct (IH b' (ltac:(firstorder')) a c' d') as [na [ [nc' [ [ [Hna [ [Hnc' ]]]]]]]].
        2-3:easy. 1: apply leq_trans with b; firstorder. 1: eapply leq_trans with c; firstorder. 1: eapply leq_trans with d; firstorder.
        exists na, (S nb'), (S nc'), (1+nb'+nd').
        recsplit 4.
        + cbn. cbn in , .
          assert ( = nd') as by congruence.
          assert ( = nd') as by congruence.
          assert ( = nb') as by congruence.
          split;nia.
        + easy.
        + destruct (f b) as [nb|] eqn:Hfb. 2: exfalso;now eapply with b.
          f_equal. symmetry. erewrite . 1: exact Hb'. all:easy.
        + destruct (f c) as [nc|] eqn:Hfc. 2: exfalso;now eapply with c.
          f_equal. symmetry. erewrite . 1: exact Hc'. all:easy.
        + assert (f d = Some nd) as by easy.
          f_equal. cbn in *; nia.
      Qed.


      Definition chain_env (f:D option ) : D := k match f k with Some l l | None 0 end.

      Lemma translate_single_correct (e:env D) (h10v : h10upc) zz n f : zz > highest_var h10v
       chain m n f ( k, k = e (k+zz))
       e translate_single h10v zz
       h10upc_sem ( k chain_env f (e k)) h10v.
      Proof using vTrans vSucc vDescr fini decP Hrho.
      destruct h10v as [[a b][c d]].
      intros Hv ch Hrhok [[[[Hrel Ha] Hb] Hc] Hd]. rewrite ! to_leq in Ha,Hb,Hc,Hd.
      pose proof Hrhok 0 as . cbn in . rewrite in Ha,Hb,Hc,Hd.
      rewrite Hrho in Ha,Hb,Hc,Hd. cbn in Ha,Hb,Hc,Hd.
      rewrite to_rel in Hrel.
      destruct (chain_proves ch Hb Hrel) as [na [nb [nc [nd [Hsem [Hna [Hnb [Hnc Hnd]]]]]]]].
      1-3: easy.
      unfold h10upc_sem, chain_env. rewrite !Hna,!Hnb,!Hnc,!Hnd. cbn in Hsem. cbn. nia.
      Qed.


      Lemma translate_list_correct (e:env D) zz n f : zz > highest_var_list
       chain m n f ( k, k = e (k+zz))
       e translate_list zz
       h10v, In h10v h10upc_sem ( k chain_env f (e k)) h10v.
      Proof using vTrans vSucc vDescr fini decP Hrho.
      intros Hv ch Hrhok Hl h10v. induction as [|h10x h10r IH] in Hl,Hrhok,ch,Hv|-*.
      - intros [].
      - destruct Hl as [ ]. intros [Hin|Hr].
        + subst h10x. apply (@translate_single_correct e h10v zz n f). 2-4:easy. cbn in Hv. .
        + apply IH. 2-5:easy. cbn in Hv. .
      Qed.


    End withAxioms.

    Lemma remove_emplace_exists r frm n : r emplace_exists n frm
     rr, rr frm k, r k = rr (k+n).
    Proof.
    unfold emplace_exists. intros H. induction n as [|n IH] in H,frm|-*.
    - exists r. split. 1:easy. intros k. now rewrite Nat.add_0_r.
    - rewrite it_shift in H. destruct (IH _ H) as [rr [[d Hd] Hrrr]].
      exists (d .: rr). split. 1:easy.
      intros k. rewrite Nat.add_succ_r. cbn. now apply Hrrr.
    Qed.


    Lemma F_correct : F H10UPC_SAT .
    Proof using fini decP.
    intros [z [m [[[[[vpTrans vpPred] vpSucc] vpDescr] ] [ [Hlist Hrho]]%remove_emplace_exists]]].
    assert (H10UPC_SAT iN m) as [Hl|Nm].
    - destruct as [|h10v h10r]. 1:left;exists ( _ 0); intros k [].
      right. destruct Hlist as [Hr _]. destruct h10v as [[ha hb][hc hd]]. cbn in Hr.
      rewrite ! to_leq in Hr. destruct Hr as [_ [_ [Hr _]]]. specialize (Hrho 0). cbn in Hrho. congruence.
    - easy.
    - destruct (@mkchain m z (m.:z.:) eq_refl vpTrans vpPred vpSucc m Nm) as [n [f c]].
      exists ( k chain_env f ( k)).
      apply (@translate_list_correct m z (m.:z.:) eq_refl vpTrans vpSucc vpDescr (S(highest_var_list )) n f ltac:()). all:easy.
    Qed.

  End inverseTransport.

  Section transport.
  Context {rho: }.
  Context {H10sat : k, In k h10upc_sem k}.
  Inductive finNum (m:) : Type := fN : n, n m finNum m.

  Lemma le0 {m} : 0 m. Proof. . Qed.
  Lemma leS {n m} : n m S n S m. Proof. . Qed.

  Lemma finNum_eq m (f1 f2 : finNum m) : {=}+{}.
  Proof.
    destruct as [ ], as [ ].
    destruct (eq_nat_decide ) as [Heq|Hne]; rewrite eq_nat_is_eq in *.
    - subst. left. f_equal. apply le_unique.
    - right. congruence.
  Defined.


  Lemma finNum_fin m : cListable (finNum m).
  Proof.
  induction m as [|m [l IHl]].
  - exists ((fN le0)::nil). intros [n u]. assert (n=0) as by . left. f_equal. apply le_unique.
  - exists ((fN le0)::map ( k match k with @fN _ n u fN (leS u) end) l).
    intros [[|n] u].
    + left. f_equal. apply le_unique.
    + right. rewrite in_map_iff. assert (n m) as Hu by . exists (fN Hu). split.
      * f_equal. apply le_unique.
      * apply IHl.
  Qed.


  Inductive model (m:) : Type := Num : finNum m model m | Pair : finNum m finNum m model m.

  Lemma model_fin m : cListable (model m).
  Proof.
  destruct (finNum_fin m) as [l Hl].
  exists (map (@Num m) l flat_map ( v map (Pair v) l) l).
  intros [n|a b].
  - apply in_or_app. left. apply in_map, Hl.
  - apply in_or_app. right. rewrite in_flat_map. exists a. split. 1:apply Hl.
    apply in_map, Hl.
  Qed.


  Definition model_rel (m:) (a b : model m) : Prop := match (a,b) with
  (Num (@fN _ _), Num (@fN _ _))
| (Pair _ (@fN _ r _), Num (@fN _ n _)) r = n
| (Num (@fN _ n _), Pair (@fN _ l _) _) n = l
| (Pair (@fN _ a _) (@fN _ b _), Pair (@fN _ c _) (@fN _ d _)) h10upc_sem_direct ((a,b),(c,d)) end.

  Instance model_interp m : interp (model m).
  Proof. split.
  - intros [].
  - intros []. cbn. intros [l r]%proj_vec2.
    exact (@model_rel m l r).
  Defined.


  Lemma leq_dec a b : sum (ab) (a b False).
  Proof.
  induction a as [|a IH] in b|-*.
  - left. .
  - destruct b as [|b].
    + right. .
    + destruct (IH b) as [IHl|IHr]; [left|right]; .
  Defined.


  Definition into_fin m k := match leq_dec k m with inl u fN u | _ fN le0 end.

  Definition m := S (highest_num (highest_var_list )).
  Definition myenv k := Num (into_fin m ( k)).

  Lemma myenv_desc i : i highest_var_list (H: i m), myenv i = Num (fN H).
  Proof.
  intros H. unfold myenv, into_fin, m. pose proof (highest_num_descr _ _ H) as Hpr.
  assert ( i S (highest_num (highest_var_list ))) as by .
  exists . destruct leq_dec as [Hl|Hr].
  - f_equal. f_equal. apply le_unique.
  - exfalso. now apply Hr, .
  Qed.


  Notation "a # b" := (@model_rel m a b) (at level 50).

  Ltac solve_m := (unfold m;).

  Lemma m_N m (e : env (model m)) (a : ) : e N a n1 u1, (e a) = Num (@fN _ ).
  Proof. split.
  - cbn -[model_rel]. destruct (e a) as [[ ]|l r].
    + exists , . easy.
    + destruct l as [nl ul], r as [nr ur]. unfold model_rel. intros H. exfalso. apply (h10_rel_irref _ H).
  - intros [ [ Heq]]. cbn. rewrite Heq. .
  Qed.


  Lemma m_P' m (e : env (model m)) (a : ) : e P' a nl ul nr ur, (e a) = Pair (@fN _ nl ul) (@fN _ nr ur).
  Proof. split.
  - cbn -[model_rel]. destruct (e a) as [[ ]|[nl ul] [nr ur]].
    + intros H. exfalso. unfold model_rel in H. apply H. .
    + unfold model_rel. intros H. exists nl, ul, nr, ur. easy.
  - intros [nl [ul [nr [ur Heq]]]]. cbn. rewrite Heq. .
  Qed.


  Lemma m_P m (e : env (model m)) (p a b : ) : e P p a b n1 u1 n2 u2, (e a) = Num (@fN _ ) (e b) = Num (@fN _ ) (e p) = Pair (@fN _ ) (@fN _ ).
  Proof. split.
  - intros [[[[[nl' [ul' [nr' [ur' ]]]]%m_P' [nl [ul Hl]]%m_N] [nr [ur Hr]]%m_N] ] ]. exists nl, ul, nr, ur. split. 2:split. 1-2:easy.
    rewrite . cbn in , . rewrite , Hl in . rewrite , Hr in . subst nl'. subst nr'. f_equal; f_equal; apply le_unique.
  - intros [nl [ul [nr [ur [Hl [Hr Hp]]]]]]. cbn -[model_rel]. split. 1:split. 1:split. 1:split.
    + change (e P' p). rewrite m_P'. eauto.
    + change (e N a). rewrite m_N. eauto.
    + change (e N b). rewrite m_N. eauto.
    + cbn. rewrite Hl, Hp. easy.
    + cbn. rewrite Hr, Hp. easy.
  Qed.


  Lemma differentNums (m:) (base:finNum m) : m > 0 (m1 m2 : finNum m), (
    (model_rel (Num ) (Num base) model_rel (Num ) (Num base))
  \/(model_rel (Num base) (Num ) model_rel (Num base) (Num ))
  ).
  Proof.
  intros .
  destruct base as [[|n] Hn].
  * eexists (@fN m 0 _).
    eexists (@fN m 1 _).
    split.
    - intros H. congruence.
    - right. cbn. .
  * eexists (@fN m 0 _).
    eexists (@fN m 1 _).
    split.
    - intros H. congruence.
    - left. cbn. .
  Unshelve. all: .
  Qed.


  Lemma m_deq (m:) (e : env (model m)) (l r : ) : m > 0 e deq l r e l = e r.
  Proof. intros .
  destruct (e l) as [[ ]|[a Ha] [b Hb]] eqn:Hel, (e r) as [[ ]|[c Hc] [d Hd]] eqn:Her; split.
  * unfold deq. intros H. specialize (H (Pair (fN ) (fN ))). cbn in H. rewrite Hel, Her in H. assert ( = ) as by firstorder congruence. do 2 f_equal. apply le_unique.
  * cbn -[model_rel]. intros H d. unfold model_rel. rewrite Hel,Her. cbn. assert ( = ) as by firstorder congruence. firstorder.
  * intros H. change H with ( d : model m, ((d # e l d # e r)) (e l # d e r # d)). destruct (differentNums (fN ) ) as [ [ [ [[Hm2a1 Hm2a2]|[Hm2b1 Hm2b2]]]]];
    pose proof (H (Num )) as [ ]; pose proof (H (Num )) as [ ]; destruct as [ ], as [ ]; cbn -[model_rel] in *; rewrite Hel in *; rewrite Her in *.
    - contradict . apply (proj1 ) in Hm2a1. apply (proj1 ) in Hm2a2. assert ( = ) as by congruence. f_equal. apply le_unique.
    - contradict . apply (proj1 ) in Hm2b1. apply (proj1 ) in Hm2b2. assert ( = ) as by congruence. f_equal. apply le_unique.
  * intros H. discriminate.
  * intros H. destruct (differentNums (fN ) ) as [ [ [ [[Hm2a1 Hm2a2]|[Hm2b1 Hm2b2]]]]];
    pose proof (H (Num )) as [ ]; pose proof (H (Num )) as [ ]; destruct as [ ], as [ ]; cbn -[model_rel] in *; rewrite Hel in *; rewrite Her in *.
    - contradict . apply (proj2 ) in Hm2a1. apply (proj2 ) in Hm2a2. assert ( = ) as by congruence. f_equal. apply le_unique.
    - contradict . apply (proj2 ) in Hm2b1. apply (proj2 ) in Hm2b2. assert ( = ) as by congruence. f_equal. apply le_unique.
  * intros H. discriminate.
  * intros H. pose proof (H (Num (fN Ha))) as HHa. pose proof (H (Num (fN Hb))) as HHb.
    cbn in H, HHa, HHb. cbn. f_equal. all: rewrite Hel in *; rewrite Her in *.
    - assert (a = c) as by firstorder congruence. f_equal. apply le_unique.
    - assert (d = b) as by firstorder congruence. f_equal. apply le_unique.
  * cbn -[model_rel]. rewrite !Hel,! Her. intros . firstorder.
  Qed.


  Lemma m_leq (m:) (e : env (model m)) (l r : ) : m > 0 e leq l r n1 u1 n2 u2, (e l) = Num (@fN _ ) (e r) = Num (@fN _ ) .
  Proof. split.
  - intros [[[nl [ul Hl]]%m_N [nr [ur Hr]]%m_N]Hlr]. exists nl,ul,nr,ur. split. 2:split. 1-2:easy.
    cbn in Hlr. rewrite Hl, Hr in Hlr. easy.
  - intros [nl [ul [nr [ur [Hl [Hr Hlr]]]]]]. cbn -[model_rel]. rewrite Hl, Hr. cbn. repeat split; .
  Qed.


  Lemma m_less (m:) (e : env (model m)) (l r : ) : m > 0 e less l r n1 u1 n2 u2, (e l) = Num (@fN _ ) (e r) = Num (@fN _ ) < .
  Proof. split.
  - intros [[nl [ul [nr [ur [Hl [Hr Hlr]]]]]]%m_leq Hneq]. 2:easy. exists nl,ul,nr,ur. split. 2:split. 1-2:easy. enough (nl nr) by .
    intros Hc. cbn -[deq] in Hneq. apply Hneq. erewrite m_deq. 2:easy. rewrite Hl, Hr. f_equal. subst nl. f_equal. apply le_unique.
  - intros [nl [ul [nr [ur [Hl [Hr Hlr]]]]]]. cbn -[deq leq]. split.
    + apply m_leq. 1:easy. exists nl,ul,nr,ur. split. 1:easy. split. 1:easy. .
    + intros Hc. enough (nl = nr) by . rewrite m_deq in Hc. 2:easy. rewrite Hl,Hr in Hc. congruence.
  Qed.


  Lemma m_rel (m:) (e : env (model m)) (a b c d : ) : m > 0 e rel a b c d na ua nb ub nc uc nd ud,
   (e a) = Num (@fN _ na ua) (e b) = Num (@fN _ nb ub) (e c) = Num (@fN _ nc uc) (e d) = Num (@fN _ nd ud) h10upc_sem_direct ((na,nb),(nc,nd)).
  Proof. intros . split.
  - cbn -[model_rel P]. intros [pl [pr [[[na [ua [nb [ub [Ha [Hb Hpl]]]]]]%m_P [nc [uc [nd [ud [Hc [Hd Hpr]]]]]]%m_P] Hpp]]].
    exists na,ua,nb,ub,nc,uc,nd,ud. split. 2: split. 3:split. 4:split. 1-4:easy.
    cbn in Hpl,Hpr,Ha,Hb,Hc,Hd. rewrite Hpr,Hpl in Hpp. apply Hpp.
  - intros [na [ua [nb [ub [nc [uc [nd [ud [Ha [Hb [Hc [Hd Hrel]]]]]]]]]]]]. cbn -[model_rel P].
    exists (Pair (fN ua) (fN ub)), (Pair (fN uc) (fN ud)). split. 1:split. 3:easy.
    + rewrite m_P. exists na,ua,nb,ub. tauto.
    + rewrite m_P. exists nc,uc,nd,ud. tauto.
  Qed.


  Opaque N leq P' P deq less rel.

  Lemma prove_exists m (e:env (model m)) frm n ee : ( k if leq_dec (S k) n then ee k else e (k-n)) frm e emplace_exists n frm.
  Proof.
  unfold emplace_exists. induction n as [|n IH] in frm,e,ee|-*.
  - cbn. intros H. eapply sat_ext. 2:exact H. intros x. cbn. f_equal. .
  - cbn -[leq_dec]. intros H. exists (ee n). apply IH with ee.
    eapply sat_ext. 2:exact H. intros x. cbn -[leq_dec].
    destruct (leq_dec (S x) n) as [Hl|Hr], (leq_dec (S x) (S n)) as [|].
    + easy.
    + .
    + assert (x=n) as by . assert (n-n=0) as by . easy.
    + assert (S x > n) as Hxn by . assert (x-n = S (x-S n)) as by . easy.
  Qed.



  Lemma valid (e:env (model m)) : e F.
  Proof using H10sat.
  exists (Num (fN le0)). exists (Num(into_fin m m)). split. 1:split. 1:split. 1:split. 1:split.
  - cbn. intros x y z. rewrite ! m_less; cbn. 2-4: solve_m. intros [ [ [ [ [Hx [Hy Hr]]]]]] [ [ [ [ [Hy' [Hz ]]]]]]. exists ,,,. split. 2:split. 1-2:easy. enough ( = ) by . rewrite Hy in Hy'. congruence.
  - cbn. unfold succ. intros k. rewrite m_N, m_deq. 2:solve_m. cbn.
    intros [ [ ]] . assert ( 0) as .
    + intros Hc. apply . subst . f_equal. f_equal. apply le_unique.
    + destruct as [|]. 1:. assert ( m) as by . exists (Num (fN )). rewrite m_rel.
      2:solve_m. exists ,,0,le0,(S ),,0,le0. cbn. repeat split. .
  - cbn. intros l r. rewrite !m_N, m_rel, m_less. 2-3:solve_m. cbn.
    intros [nl [ul ]] [nr [ur ]] [na [ua [nb [ub [nc [uc [nd [ud [ [Hnb [ [ H]]]]]]]]]]]]. split.
    + exists na,ua,nc,uc. repeat split. .
    + intros k. rewrite ! m_less, ! m_leq. 2-3:solve_m. cbn.
      intros [nk [uk [nc' [uc' [ [ ]]]]]].
      exists nk,uk,na,ua. repeat split. 1:easy. assert (nc = nc') as by congruence.
      enough (nb = 0) by . congruence.
  - unfold aDescr. intros a b c d [na [ua Ha]]%m_N [nb [ub Hb]]%m_N [nc [uc Hc]]%m_N [nd [ud Hd]]%m_N.
    cbn in Ha,Hb,Hc,Hd. cbn. rewrite !m_deq. 2:solve_m. unfold succ.
    cbn. intros Hnz. rewrite !m_rel. 2:solve_m. rewrite Ha,Hb,Hc,Hd. cbn.
    intros [na' [ua' [nb' [ub' [nc' [uc' [nd' [ud' [Ha' [Hb' [Hc' [Hd' H]]]]]]]]]]]].
    assert (na = na') as by congruence.
    assert (nb = nb') as by congruence.
    assert (nc = nc') as by congruence.
    assert (nd = nd') as by congruence.
    assert (nb' 0) as . 1: { intros Hcc. apply Hnz. rewrite Hb. f_equal. subst nb'. f_equal. apply le_unique. }
    destruct nb' as [|nb']. 1:.
    assert (nc' 0) as by .
    destruct nc' as [|nc']. 1:.
    assert (nb' m) as Hnb' by .
    assert (nc' m) as Hnc' by .
    assert (nd'-nb'-1 m) as Hnd' by .
    exists (Num (fN Hnb')), (Num (fN Hnc')), (Num (fN Hnd')).
    rewrite !m_rel. 2-5:solve_m. cbn -[h10upc_sem_direct].
    split. 1:split. 1:split. 1:split.
    + exists nb',Hnb',0,le0,(S nb'),ub,0,le0. repeat split; .
    + exists nc',Hnc',0,le0,(S nc'),uc,0,le0. repeat split; .
    + exists (nd'-nb'-1),Hnd',nb',Hnb',nd',ud,(nd'-nb'-1),Hnd'. repeat split; .
    + exists na',ua,nb',Hnb',nc',Hnc',(nd'-nb'-1),Hnd'. repeat split; .
    + rewrite ! m_less. 2:solve_m. cbn. exists (nd' - nb' - 1), Hnd',nd',ud. split. 1:easy. split. 1:easy. .
  - unfold . intros a b c d [na [ua Ha]]%m_N [nb [ub Hb]]%m_N [nc [uc Hc]]%m_N [nd [ud Hd]]%m_N.
    intros [na' [ua' [nb' [ub' [nc' [uc' [nd' [ud' [Ha' [Hb' [Hc' [Hd' H]]]]]]]]]]]]%m_rel.
    2:solve_m. cbn in *. rewrite ! m_deq. 2-3:solve_m. cbn. intros . rewrite Hd'. assert (nb' = 0) as by congruence.
    assert (nd' = 0) as Hnd' by . subst nd'. f_equal. f_equal. apply le_unique.
  - eapply prove_exists with myenv.
    pose (highest_var_list ) as . fold .
    assert (highest_var_list ) as Hvl by easy.
    induction as [|h10v h10r IH] in H10sat,Hvl|-*.
    + cbn. tauto.
    + cbn -[leq_dec]. split.
      * destruct h10v as [[a b][c d]]. unfold translate_single.
        cbn in Hvl.
        destruct (@myenv_desc a) as [ua Ha]. 1:.
        destruct (@myenv_desc b) as [ub Hb]. 1:.
        destruct (@myenv_desc c) as [uc Hc]. 1:.
        destruct (@myenv_desc d) as [ud Hd]. 1:.
        split. 1:split. 1:split. 1:split.
        -- rewrite m_rel. 2:solve_m.
           exists ( a). exists ua.
           exists ( b). exists ub.
           exists ( c). exists uc.
           exists ( d). exists ud.
           repeat destruct leq_dec. 2-16:.
           split. 2:split. 3:split. 4:split. 1-4:easy.
           apply (@H10sat ((a,b),(c,d))). now left.
        -- rewrite m_leq. 2:solve_m. unfold into_fin. destruct (leq_dec m m) as [Hml|Hmnl]; repeat destruct leq_dec.
           1,3,5,7,6,4:. 2:.
           exists ( a), ua, m, Hml. split. 1:easy. split. 1: assert ( k,k-k=0) as by . 2:. cbn. easy.
        -- rewrite m_leq. 2:solve_m. unfold into_fin. destruct (leq_dec m m) as [Hml|Hmnl]; repeat destruct leq_dec.
           1,3,5,7,6,4:. 2:.
           exists ( b), ub, m, Hml. split. 1:easy. split. 1: assert ( k,k-k=0) as by . 2:. cbn. easy.
        -- rewrite m_leq. 2:solve_m. unfold into_fin. destruct (leq_dec m m) as [Hml|Hmnl]; repeat destruct leq_dec.
           1,3,5,7,6,4:. 2:.
           exists ( c), uc, m, Hml. split. 1:easy. split. 1: assert ( k,k-k=0) as by . 2:. cbn. easy.
        -- rewrite m_leq. 2:solve_m. unfold into_fin. destruct (leq_dec m m) as [Hml|Hmnl]; repeat destruct leq_dec.
           1,3,5,7,6,4:. 2:.
           exists ( d), ud, m, Hml. split. 1:easy. split. 1: assert ( k,k-k=0) as by . 2:. cbn. easy.

      * apply IH.
        -- intros k Hk. apply H10sat. now right.
        -- cbn in Hvl. .
  Qed.

  End transport.

  Lemma rel_decider m (a b : model m) : dec (model_rel a b).
  Proof.
  destruct a as [[an al]|la ra], b as [[bn bl]|lb rb].
  - cbn. unfold dec. destruct (leq_dec an bn); auto.
  - cbn. unfold dec. destruct lb; decide equality.
  - cbn. destruct la,ra; unfold dec. decide equality.
  - cbn. destruct la,ra,lb,rb. apply and_dec; unfold dec; decide equality.
  Qed.


  Lemma decider_of_annoying_type m : t (model m) (ar_preds tt) bool.
  Proof.
  intros [x y]%proj_vec2.
  destruct (rel_decider x y ) as [Hl|Hr].
  - exact true.
  - exact false.
  Defined.


  Lemma m_listable m : listable (model m).
  Proof.
    destruct (model_fin m) as [ls Hls]. now exists ls.
  Qed.


  Lemma m_decidable m : ( p, decidable ( v i_atom (interp := model_interp m) (P:=p) v)).
  Proof.
    intros [ ]. exists (@decider_of_annoying_type m). intros v. unfold decider_of_annoying_type.
    cbn. destruct (proj_vec2 ) as [l r].
    destruct (@rel_decider m l r) as [Ht|Hf] eqn:Heq.
    * unfold reflects; tauto.
    * unfold reflects. split. 1:intros k;exfalso;apply Hf;easy. intros Hc. congruence.
  Qed.


  Lemma m_discrete m : discrete (model m).
  Proof.
    assert ( (d1 d2 : model m), {=}+{}) as Heq by (intros ; repeat decide equality; apply finNum_eq).
    eexists ( '(a, b) if Heq a b then true else false).
    intros [a b]. split; intros ?; destruct (Heq a b); congruence.
  Defined.


End Fsat.

Section result.
  Lemma fsat_reduction : reduction (@F) H10UPC_SAT FSAT.
  Proof.
  intros Hl. split.
  - intros [ H]. pose (@m Hl ) as m. exists (model m). exists (model_interp m). exists ( _ Num (fN le0)). split. 2:split.
    + apply m_listable.
    + apply m_decidable.
    + apply (@valid Hl H).
  - intros [D [I [ [lst [tdec H]]]]]. specialize (tdec tt).
    destruct lst as [l Hlst]. destruct tdec as [f Hf].
    apply (@F_correct Hl D I ).
    + intros a b. cbn. destruct (f (Vector.cons D a 1 (Vector.cons D b 0 (Vector.nil D)))) as [|] eqn:Hdec.
      * left. now apply Hf.
      * right. intros Hc. apply Hf in Hc. congruence.
    + exists l. exact Hlst.
    + exact H.
  Qed.


  Lemma fval_reduction : reduction ( k @F k falsity) ( l (H10UPC_SAT l)) FVAL.
  Proof.
  intros Hl. split.
  - intros Hc D I [lst tdec] H. apply Hc.
    destruct lst as [l Hlst]. destruct (tdec tt) as [f Hf].
    apply (@F_correct Hl D I ).
    + intros a b. cbn. destruct (f (Vector.cons D a 1 (Vector.cons D b 0 (Vector.nil D)))) as [|] eqn:Hdec.
      * left. now apply Hf.
      * right. intros . apply Hf in . congruence.
    + exists l. exact Hlst.
    + exact H.
  - intros Hc [ H]. pose (@m Hl ) as m. specialize (Hc (model m)). specialize (Hc (model_interp m)). specialize (Hc ( _ Num (fN le0))). apply Hc. 1: split.
    + apply m_listable.
    + apply m_decidable.
    + apply (@valid Hl H).
  Qed.


  Lemma fsatd_reduction : reduction (@F) H10UPC_SAT FSATd.
  Proof.
  intros Hl. split.
  - intros [ H]. pose (@m Hl ) as m. exists (model m). exists (model_interp m). exists ( _ Num (fN le0)). repeat split.
    + apply m_listable.
    + apply m_discrete.
    + apply m_decidable.
    + apply (@valid Hl H).
  - intros [D [I [ [lst [tdisc [tdec H]]]]]]. specialize (tdec tt).
    destruct lst as [l Hlst]. destruct tdec as [f Hf].
    apply (@F_correct Hl D I ).
    + intros a b. cbn. destruct (f (Vector.cons D a 1 (Vector.cons D b 0 (Vector.nil D)))) as [|] eqn:Hdec.
      * left. now apply Hf.
      * right. intros Hc. apply Hf in Hc. congruence.
    + exists l. exact Hlst.
    + exact H.
  Qed.


  Definition F_cform (h:list h10upc) : cform := exist _ (@F h) (ltac:(apply F_closed)).

  Lemma fsatdc_reduction : reduction (@F_cform) H10UPC_SAT FSATdc.
  Proof.
  intros Hl. unfold F_cform. split.
  - intros [ H]. pose (@m Hl ) as m. exists (model m). exists (model_interp m). exists ( _ Num (fN le0)). repeat split.
    + apply m_listable.
    + apply m_discrete.
    + apply m_decidable.
    + apply (@valid Hl H).
  - intros [D [I [ [lst [tdisc [tdec H]]]]]]. specialize (tdec tt).
    destruct lst as [l Hlst]. destruct tdec as [f Hf].
    apply (@F_correct Hl D I ).
    + intros a b. cbn. destruct (f (Vector.cons D a 1 (Vector.cons D b 0 (Vector.nil D)))) as [|] eqn:Hdec.
      * left. now apply Hf.
      * right. intros Hc. apply Hf in Hc. congruence.
    + exists l. exact Hlst.
    + exact H.
  Qed.


  Notation FSAT_frag := Fragment.FSAT.
  Notation FSATd_frag := Fragment.FSATd.
  Notation FSATdc_frag := Fragment.FSATdc.
  Notation FVAL_frag := Fragment.FVAL.

  Definition frag_reduction_fsat : reduction (translate_form) FSAT FSAT_frag.
  Proof.
  intros f. split.
  - intros [D [I [ [Hl [Hd Hsat]]]]]. exists D. exists (full_tarski_tarski_interp I). exists . split. 2:split.
    + easy.
    + setoid_rewrite eval_same_atom. rewrite (full_interp_inverse_1 I). apply Hd.
    + destruct Hl as [ll Hll]. destruct (Hd tt) as [df Hf]. edestruct (@DoubleNegation.correct _ _ D (full_tarski_tarski_interp I)) as [HH _].
      2: rewrite HH, (full_interp_inverse_1 I); apply Hsat.
      intros ff fm e. apply general_decider.
      * now exists ll.
      * intros ff' [] t ee. cbn. destruct (df (Vector.map (eval ee) t)) eqn:Heq.
        ++ left. unfold decider,reflects in Hf. rewrite (full_interp_inverse_1 I), Hf. easy.
        ++ right. unfold decider,reflects in Hf. rewrite (full_interp_inverse_1 I), Hf. cbn in Heq. congruence.
  - intros [D [I [ [Hl [Hd Hsat]]]]]. exists D. exists (tarski_full_tarski_interp I). exists . split. 2:split.
    + easy.
    + intros [ ]. setoid_rewrite eval_same_atom. apply Hd.
    + destruct Hl as [ll Hll]. destruct (Hd tt) as [df Hf]. edestruct (@DoubleNegation.correct _ _ D I) as [HH _].
      2: now rewrite HH.
      intros ff fm e. apply general_decider.
      * now exists ll.
      * intros ff' [] t ee. cbn. destruct (df (Vector.map (@eval _ _ _ (tarski_full_tarski_interp I) ee) t)) eqn:Heq.
        ++ left. unfold decider,reflects in Hf. rewrite Hf in Heq. rewrite eval_same_atom. exact Heq.
        ++ right. unfold decider,reflects in Hf. rewrite eval_same_atom, Hf. cbn in Heq. congruence.
  Qed.


  Definition frag_reduction_fval : reduction (translate_form) FVAL FVAL_frag.
  Proof.
  intros f. split.
  - intros Hval D I [Hl Hd]. specialize (@Hval D (tarski_full_tarski_interp I) ).
    destruct Hl as [ll Hll]. destruct (Hd tt) as [df Hf].
    edestruct (@DoubleNegation.correct _ _ D I) as [HH [ [ ]]].
    + intros ff fm e. apply general_decider.
      * now exists ll.
      * intros ff' [] t ee. cbn. destruct (df (Vector.map (@eval _ _ _ (tarski_full_tarski_interp I) ee) t)) eqn:Heq.
        ++ left. unfold decider,reflects in Hf. rewrite Hf in Heq. rewrite eval_same_atom. exact Heq.
        ++ right. unfold decider,reflects in Hf. rewrite eval_same_atom, Hf. cbn in Heq. congruence.
    + rewrite HH. apply Hval. split. 1: now exists ll.
      setoid_rewrite eval_same_atom. intros [ ]. now exists df.
  - intros Hval D I [Hl Hd]. specialize (@Hval D (full_tarski_tarski_interp I) ).
    destruct Hl as [ll Hll]. destruct (Hd tt) as [df Hf].
    enough ( (ff:falsity_flag) f e, dec (@sat _ _ _ (tarski_full_tarski_interp (full_tarski_tarski_interp I)) ff e f)) as HH.
    + edestruct (@DoubleNegation.correct _ _ D (full_tarski_tarski_interp I) HH _ f) as [ _].
      rewrite (full_interp_inverse_1 I) in . rewrite . apply Hval. split.
      * now exists ll.
      * intros []. exists df. setoid_rewrite eval_same_atom. intros k. rewrite (full_interp_inverse_1 I). apply Hf.
    + intros ff fm e. apply general_decider.
      * now exists ll.
      * intros ff' [] t ee. cbn. destruct (df (Vector.map (eval ee) t)) eqn:Heq.
        ++ left. unfold decider,reflects in Hf. rewrite (full_interp_inverse_1 I), Hf. easy.
        ++ right. unfold decider,reflects in Hf. rewrite (full_interp_inverse_1 I), Hf. cbn in Heq. congruence.
  Qed.


  Definition frag_reduction_fsatd : reduction (translate_form) FSATd FSATd_frag.
  Proof.
  intros f. split.
  - intros [D [I [ [Hl [Hdisc [Hd Hsat]]]]]]. exists D. exists (full_tarski_tarski_interp I). exists . repeat split.
    + easy.
    + easy.
    + setoid_rewrite eval_same_atom. rewrite (full_interp_inverse_1 I). apply Hd.
    + destruct Hl as [ll Hll]. destruct (Hd tt) as [df Hf]. edestruct (@DoubleNegation.correct _ _ D (full_tarski_tarski_interp I)) as [HH _].
      2: rewrite HH, (full_interp_inverse_1 I); apply Hsat.
      intros ff fm e. apply general_decider.
      * now exists ll.
      * intros ff' [] t ee. cbn. destruct (df (Vector.map (eval ee) t)) eqn:Heq.
        ++ left. unfold decider,reflects in Hf. rewrite (full_interp_inverse_1 I), Hf. easy.
        ++ right. unfold decider,reflects in Hf. rewrite (full_interp_inverse_1 I), Hf. cbn in Heq. congruence.
  - intros [D [I [ [Hl [Hdisc [Hd Hsat]]]]]]. exists D. exists (tarski_full_tarski_interp I). exists . repeat split.
    + easy.
    + easy.
    + intros [ ]. setoid_rewrite eval_same_atom. apply Hd.
    + destruct Hl as [ll Hll]. destruct (Hd tt) as [df Hf]. edestruct (@DoubleNegation.correct _ _ D I) as [HH _].
      2: now rewrite HH.
      intros ff fm e. apply general_decider.
      * now exists ll.
      * intros ff' [] t ee. cbn. destruct (df (Vector.map (@eval _ _ _ (tarski_full_tarski_interp I) ee) t)) eqn:Heq.
        ++ left. unfold decider,reflects in Hf. rewrite Hf in Heq. rewrite eval_same_atom. exact Heq.
        ++ right. unfold decider,reflects in Hf. rewrite eval_same_atom, Hf. cbn in Heq. congruence.
  Qed.


  Definition frag_reduction_fsatdc : reduction (translate_form_closed) FSATdc FSATdc_frag.
  Proof.
  intros [f Hfclosed]. split.
  - intros [D [I [ [Hl [Hdisc [Hd Hsat]]]]]]. exists D. exists (full_tarski_tarski_interp I). exists . repeat split.
    + easy.
    + easy.
    + setoid_rewrite eval_same_atom. rewrite (full_interp_inverse_1 I). apply Hd.
    + destruct Hl as [ll Hll]. destruct (Hd tt) as [df Hf]. cbn. edestruct (@DoubleNegation.correct _ _ D (full_tarski_tarski_interp I)) as [HH _].
      2: rewrite HH, (full_interp_inverse_1 I); apply Hsat.
      intros ff fm e. apply general_decider.
      * now exists ll.
      * intros ff' [] t ee. cbn. destruct (df (Vector.map (eval ee) t)) eqn:Heq.
        ++ left. unfold decider,reflects in Hf. rewrite (full_interp_inverse_1 I), Hf. easy.
        ++ right. unfold decider,reflects in Hf. rewrite (full_interp_inverse_1 I), Hf. cbn in Heq. congruence.
  - intros [D [I [ [Hl [Hdisc [Hd Hsat]]]]]]. exists D. exists (tarski_full_tarski_interp I). exists . repeat split.
    + easy.
    + easy.
    + intros [ ]. setoid_rewrite eval_same_atom. apply Hd.
    + destruct Hl as [ll Hll]. destruct (Hd tt) as [df Hf]. edestruct (@DoubleNegation.correct _ _ D I) as [HH _].
      2: now rewrite HH.
      intros ff fm e. apply general_decider.
      * now exists ll.
      * intros ff' [] t ee. cbn. destruct (df (Vector.map (@eval _ _ _ (tarski_full_tarski_interp I) ee) t)) eqn:Heq.
        ++ left. unfold decider,reflects in Hf. rewrite Hf in Heq. rewrite eval_same_atom. exact Heq.
        ++ right. unfold decider,reflects in Hf. rewrite eval_same_atom, Hf. cbn in Heq. congruence.
  Qed.


End result.