(**************************************************************)
(*   Copyright Dominique Larchey-Wendling [*]                 *)
(*                                                            *)
(*                             [*] Affiliation LORIA -- CNRS  *)
(**************************************************************)
(*      This file is distributed under the terms of the       *)
(*         CeCILL v2 FREE SOFTWARE LICENSE AGREEMENT          *)
(**************************************************************)

(** ** Elementary diophantine constraints *)

Require Import List Arith Nat Omega.
Require Import utils_list gcd prime dio_logic.

Set Implicit Arguments.

Section interval.

  (** A small interval & valuation library *)

  Definition interval := (nat * nat)%type. (* (a,b) <~~~> [a,b[ *)

  Implicit Types (i j : interval).

  Definition in_interval i x := let (a,b) := i in a <= x < b.
  Definition out_interval i x := let (a,b) := i in x < a \/ b <= x.
  Definition interval_disjoint i j := forall x, in_interval i x -> in_interval j x -> False.

  Definition interval_union (i j : interval) :=
    match i, j with (a1,b1),(a2,b2) => (min a1 a2, max b1 b2) end.

  Fact in_out_interval i x : in_interval i x -> out_interval i x -> False.
(* Goal: forall (_ : in_interval i x) (_ : out_interval i x), False *)
  Proof. destruct i; simpl; omega. Qed.

  Fact in_out_interval_dec i x : { in_interval i x } + { out_interval i x }.
  Proof. 
(* Goal: sumbool (in_interval i x) (out_interval i x) *)
    destruct i as (a,b); simpl.
(* Goal: sumbool (and (le a x) (lt x b)) (or (lt x a) (le b x)) *)
    destruct (le_lt_dec a x); destruct (le_lt_dec b x); try (left; omega);right; omega.
  Qed. 

  Fact interval_union_left i j x : in_interval i x -> in_interval (interval_union i j) x.
  Proof.
(* Goal: forall _ : in_interval j x, in_interval (interval_union i j) x *)
    revert i j; intros (a,b) (u,v); simpl.
(* Goal: forall _ : and (le a x) (lt x b), and (le (min a u) x) (lt x (max b v)) *)
    generalize (Nat.le_min_l a u) (Nat.le_max_l b v); omega.
  Qed.

  Fact interval_union_right i j x : in_interval j x -> in_interval (interval_union i j) x.
  Proof.
(* Goal: forall _ : in_interval j x, in_interval (interval_union i j) x *)
    revert i j; intros (a,b) (u,v); simpl.
(* Goal: forall _ : and (le u x) (lt x v), and (le (min a u) x) (lt x (max b v)) *)
    generalize (Nat.le_min_r a u) (Nat.le_max_r b v); omega.
  Qed.

  Definition valuation_union i1 (g1 : nat -> nat) i2 g2 : 
               interval_disjoint i1 i2 
            -> { g | (forall x, in_interval i1 x -> g x = g1 x)
                  /\ (forall x, in_interval i2 x -> g x = g2 x) }.
  Proof.
(* Goal: forall _ : interval_disjoint i1 i2, @sig (forall _ : nat, nat) (fun g : forall _ : nat, nat => and (forall (x : nat) (_ : in_interval i1 x), @eq nat (g x) (g1 x)) (forall (x : nat) (_ : in_interval i2 x), @eq nat (g x) (g2 x))) *)
    intros H2.
(* Goal: @sig (forall _ : nat, nat) (fun g : forall _ : nat, nat => and (forall (x : nat) (_ : in_interval i1 x), @eq nat (g x) (g1 x)) (forall (x : nat) (_ : in_interval i2 x), @eq nat (g x) (g2 x))) *)
    exists (fun x => if in_out_interval_dec i1 x then g1 x else g2 x).
(* Goal: and (forall (x : nat) (_ : in_interval i1 x), @eq nat (if in_out_interval_dec i1 x then g1 x else g2 x) (g1 x)) (forall (x : nat) (_ : in_interval i2 x), @eq nat (if in_out_interval_dec i1 x then g1 x else g2 x) (g2 x)) *)
    split; intros x Hx.
    + destruct (in_out_interval_dec i1 x) as [ | H3 ]; auto.
(* Goal: @eq nat (g2 x) (g1 x) *)
      exfalso; revert Hx H3; apply in_out_interval.
    + destruct (in_out_interval_dec i1 x) as [ H3 | ]; auto.
(* Goal: @eq nat (g1 x) (g2 x) *)
      exfalso; revert H3 Hx; apply H2.
  Qed.

  Definition valuation_one_union k v i1 (g1 : nat -> nat) i2 g2 : 
               ~ in_interval (interval_union i1 i2) k 
            -> interval_disjoint i1 i2 
            -> { g | g k = v /\ (forall x, in_interval i1 x -> g x = g1 x)
                             /\ (forall x, in_interval i2 x -> g x = g2 x) }.
  Proof.
(* Goal: forall (_ : forall (x : nat) (_ : dc_vars c x), @eq nat (φ1 x) (φ2 x)) (_ : forall x : nat, @eq nat (ν1 x) (ν2 x)), iff (dc_eval φ1 ν1 c) (dc_eval φ2 ν2 c) *)
    intros H1 H2.
    exists (fun x => if eq_nat_dec x k then v 
                     else if in_out_interval_dec i1 x then g1 x 
                     else g2 x).
(* Goal: and (@eq nat (if Nat.eq_dec k k then v else if in_out_interval_dec i1 k then g1 k else g2 k) v) (and (forall (x : nat) (_ : in_interval i1 x), @eq nat (if Nat.eq_dec x k then v else if in_out_interval_dec i1 x then g1 x else g2 x) (g1 x)) (forall (x : nat) (_ : in_interval i2 x), @eq nat (if Nat.eq_dec x k then v else if in_out_interval_dec i1 x then g1 x else g2 x) (g2 x))) *)
    split; [ | split ].
    + destruct (eq_nat_dec k k) as [ | [] ]; auto.
    + intros x Hx.
(* Goal: @eq nat (if Nat.eq_dec x k then v else if in_out_interval_dec i1 x then g1 x else g2 x) (g2 x) *)
      destruct (eq_nat_dec x k) as [ | ].
      * subst; destruct H1; apply interval_union_left; auto.
(* Goal: @eq nat (if in_out_interval_dec i1 x then g1 x else g2 x) (g1 x) *)
      * destruct (in_out_interval_dec i1 x) as [ | H3 ]; auto.
(* Goal: @eq nat (g2 x) (g1 x) *)
        exfalso; revert Hx H3; apply in_out_interval.
    + intros x Hx.
(* Goal: @eq nat (if Nat.eq_dec x k then v else if in_out_interval_dec i1 x then g1 x else g2 x) (g2 x) *)
      destruct (eq_nat_dec x k) as [ | ].
      * subst; destruct H1; apply interval_union_right; auto.
(* Goal: @eq nat (if in_out_interval_dec i1 x then g1 x else g2 x) (g2 x) *)
      * destruct (in_out_interval_dec i1 x) as [ H3 | ]; auto.
(* Goal: @eq nat (g1 x) (g2 x) *)
        exfalso; revert H3 Hx; apply H2.
  Qed.

End interval.

Section diophantine_system.

  (* v : cst = nat      constant (natural number)
     p q : par = nat    parameter 
     x y z : var = nat  existentially quantified variable 
   
     equations are of 4 types 
       1) x = v 
       2) x = p 
       3) x = y + z 
       4) x = y * z 

     We represent a relation between parameters R by a list of equations l and one
     variable x : var such that
       a) for any value f : nat -> nat of the params, l[f] has a solution
       b) for any value f : nat -> nat of the params,

                R f <-> ((x=0)::l)[f] has a solution

     How do we simulate poly1 = poly2 linearly ?

         poly1 = (eqn1,x) where x is output
         poly2 = (eqn2,y) where y is output

         example poly1 = p*(q+r)
         gives eqn1:= (0=1*2, 1=p, 2=3+4, 3=q, 4=r) and x:=0

         then we simulate poly1 = poly2 with
 
               poly1 = poly2 <-> (eqn1 U eqn2 U { w=y+u, w=x+v, z=u+v }, z)

         where u v z w are fresh

     We implement conjunction (cap), disjunction (cup) and exists so that we get a linear encoding

      cap) R by (lR,xR) and S by (lS,xS) 
           we assume (lR,xR) and (lS,xS) do not share existential variables
           (always possible by renaming those of S)

           R cap S = (lR U lS U { z = x+y },z) where z is fresh
 
      cup) R cup S = (lR U lS U { z = x*y },z)

      exists) ∃n.R f{p<-n} = (lR[p<-0], ...)

   *)

  Inductive dio_elem_expr : Set :=
    | dee_nat  : nat -> dio_elem_expr   (* c : constant *)
    | dee_var  : nat -> dio_elem_expr   (* v : existentially quant. var *)
    | dee_par  : nat -> dio_elem_expr   (* p : parameter *)
    | dee_comp : dio_op -> nat -> nat -> dio_elem_expr. (* v1 op v2 *)

  Notation dee_add := (dee_comp do_add).
  Notation dee_mul := (dee_comp do_mul).

  (* ρ σ ν φ *)

  Definition dee_eval φ ν e := 
    match e with
      | dee_nat n => n
      | dee_var v => φ v
      | dee_par i => ν i
      | dee_comp o v w => do_eval o (φ v) (φ w) 
    end.

  Definition dee_vars e x  :=
    match e with
      | dee_nat _ => False
      | dee_var v => x = v
      | dee_par _ => False
      | dee_comp _ v w => x = v \/ x = w
    end.

  Fact dee_eval_ext e φ1 ν1 φ2 ν2  : 
        (forall x, dee_vars e x -> φ1 x = φ2 x) 
     -> (forall x, ν1 x = ν2 x)
     -> dee_eval φ1 ν1 e = dee_eval φ2 ν2 e.
  Proof. destruct e as [ | | | [] ]; simpl; auto. Qed.

  (* ρ σ ν *)

  Definition dee_move k p :=
    match p with
      | dee_nat n      => dee_nat n
      | dee_var v      => dee_var (k+v)
      | dee_par i      => dee_par i
      | dee_comp o v w => dee_comp o (k+v) (k+w)
    end.

  Fact dee_eval_move k φ ν e : dee_eval φ ν (dee_move k e) = dee_eval (fun x => φ (k+x)) ν e.
  Proof. destruct e as [ | | | [] ]; simpl; auto. Qed.

  Fact dee_vars_move k e x : dee_vars (dee_move k e) x <-> exists y, dee_vars e y /\ x = k+y.
  Proof. destruct e as [ | | | [] ]; simpl; firstorder. Qed.

  Definition dee_dec k e :=
    match e with
      | dee_nat n      => dee_nat n
      | dee_var v      => dee_var v
      | dee_par 0      => dee_var k 
      | dee_par (S i)  => dee_par i
      | dee_comp o v w => dee_comp o v w
    end.

  Fact dee_eval_dec φ ν k e : dee_eval φ ν (dee_dec k e) = dee_eval φ (fun x => match x with 0 => φ k | S x => ν x end) e.
  Proof. destruct e as [ | | [] | [] ]; simpl; auto. Qed.

  Fact dee_vars_dec k e x : dee_vars (dee_dec k e) x -> x = k \/ dee_vars e x.
  Proof. destruct e as [ | | [] | [] ]; simpl; firstorder. Qed.

  Definition dio_constraint := (nat * dio_elem_expr)%type.

  Implicit Type (c : dio_constraint).

  Definition dc_eval φ ν c := φ (fst c) = dee_eval φ ν (snd c).

  Arguments dc_eval φ ν c /.
  
  Definition dc_vars c x := x = fst c \/ dee_vars (snd c) x.

  Arguments dc_vars c x /.

  Fact dc_eval_ext c φ1 ν1 φ2 ν2  : 
        (forall x, dc_vars c x -> φ1 x = φ2 x) 
     -> (forall x, ν1 x = ν2 x)
     -> dc_eval φ1 ν1 c <-> dc_eval φ2 ν2 c.
  Proof.
(* Goal: forall (_ : forall (x : nat) (_ : dc_vars c x), @eq nat (φ1 x) (φ2 x)) (_ : forall x : nat, @eq nat (ν1 x) (ν2 x)), iff (dc_eval φ1 ν1 c) (dc_eval φ2 ν2 c) *)
    intros H1 H2.
(* Goal: iff (dc_eval φ1 ν1 c) (dc_eval φ2 ν2 c) *)
    destruct c as (v,e); unfold dc_eval; simpl.
(* Goal: iff (@eq nat (φ1 v) (dee_eval φ1 ν1 e)) (@eq nat (φ2 v) (dee_eval φ2 ν2 e)) *)
    rewrite H1; simpl; auto.
(* Goal: iff (@eq nat (φ2 v) (dee_eval φ1 ν1 e)) (@eq nat (φ2 v) (dee_eval φ2 ν2 e)) *)
    rewrite dee_eval_ext with e φ1 ν1 φ2 ν2; try tauto.
(* Goal: forall (x : nat) (_ : dee_vars e x), @eq nat (φ1 x) (φ2 x) *)
    intros; apply H1; simpl; auto.
  Qed.

  Definition dc_move k c := (k+fst c, dee_move k (snd c)).

  Fact dc_eval_move k φ ν c : dc_eval φ ν (dc_move k c) <-> dc_eval (fun x => φ (k+x)) ν c.
  Proof.
(* Goal: iff (dc_vars (dc_move k c) x) (@ex nat (fun y : nat => and (@eq nat x (add k y)) (dc_vars c y))) *)
    destruct c as (v,e); simpl.
(* Goal: iff (@eq nat (φ (add k v)) (dee_eval φ ν (dee_move k e))) (@eq nat (φ (add k v)) (dee_eval (fun x : nat => φ (add k x)) ν e)) *)
    rewrite dee_eval_move; tauto.
  Qed.

  Fact dc_vars_move k c x : dc_vars (dc_move k c) x <-> exists y, x = k + y /\ dc_vars c y.
  Proof.
(* Goal: iff (dc_vars (dc_move k c) x) (@ex nat (fun y : nat => and (@eq nat x (add k y)) (dc_vars c y))) *)
    destruct c as (v,e); simpl.
(* Goal: iff (or (@eq nat x (add k v)) (dee_vars (dee_move k e) x)) (@ex nat (fun y : nat => and (@eq nat x (add k y)) (or (@eq nat y v) (dee_vars e y)))) *)
    rewrite dee_vars_move.
(* Goal: iff (or (@eq nat x (add k v)) (@ex nat (fun y : nat => and (dee_vars e y) (@eq nat x (add k y))))) (@ex nat (fun y : nat => and (@eq nat x (add k y)) (or (@eq nat y v) (dee_vars e y)))) *)
    split.
    + intros [ ? | (y & Hy & ?) ]; subst x; firstorder; exists v; auto.
    + intros (y & ? & [ | ]); subst; firstorder.
  Qed.

  Definition dc_dec k c := (fst c, dee_dec k (snd c)).

  Fact dc_eval_dec φ ν k c : dc_eval φ ν (dc_dec k c) <-> dc_eval φ  (fun x => match x with 0 => φ k | S x => ν x end) c.
  Proof. destruct c; simpl; rewrite dee_eval_dec; tauto. Qed.

  Fact dc_vars_dec k c x : dc_vars (dc_dec k c) x -> x = k \/ dc_vars c x.
  Proof. destruct c; simpl; intros [ | H ]; auto; apply dee_vars_dec in H; tauto. Qed.

  Implicit Type (R : (nat -> nat) -> Prop).

  (* A diophantine system for R is an interval i, a list l of constraints, a reference variable x
     such that
(* Goal: interval_disjoint (@pair nat nat a1 (add a1 n1)) (@pair nat nat a2 (add a2 n2)) *)
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2))) (@eq nat (φ (add a2 n2)) O)) *)
       1) the variables in l U {x} and belong to i
       2) for any valuation, the equations of l are satisfiable
(* Goal: interval_disjoint (@pair nat nat a1 (add a1 n1)) (@pair nat nat a2 (add a2 n2)) *)
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2))) (@eq nat (φ (add a2 n2)) O)) *)
       3) for any valuation ν, R ν holds iff the equations of { x=0 } U l are satisfiable
   *)

(* Goal: interval_disjoint (@pair nat nat a1 (add a1 n1)) (@pair nat nat a2 (add a2 n2)) *)
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2))) (@eq nat (φ (add a2 n2)) O)) *)
  Record dio_repr_at R a n l := {
    ds_eqns : list dio_constraint;
    ds_ref  : nat;
    ds_H0   : length ds_eqns = l;
    ds_H1   : forall x c, In c ds_eqns -> dc_vars c x -> a <= x < a+n;
    ds_H2   : a <= ds_ref < a+n;
    ds_H3   : forall ν, exists φ, Forall (dc_eval φ ν) ds_eqns;
    ds_H4   : forall ν, R ν <-> exists φ, Forall (dc_eval φ ν) ds_eqns /\ φ ds_ref = 0;
  }.

  Section diophantine_sys_expr.

    (* A compiler from expressions to lists of small expressions *)

    Fixpoint de_eqns e x :=
      match e with
        | de_cst n      => (x,dee_nat n)::nil 
        | de_var p      => (x,dee_par p)::nil
        | de_comp o p q => (x,dee_comp o (x+1) (x+1+de_size p)) :: de_eqns p (x+1) ++ de_eqns q (x+1+de_size p)
      end.

    Fact de_eqns_length e x : length (de_eqns e x) = de_size e.
    Proof.
(* Goal: forall (c : dio_constraint) (_ : @In dio_constraint c (de_eqns e x)) (y : nat) (_ : dc_vars c y), and (le x y) (lt y (add x (de_size e))) *)
      revert x; induction e as [ | | o p Hp q Hq ]; intros x; simpl; auto.
(* Goal: @eq nat (S (@length (prod nat dio_elem_expr) (@app (prod nat dio_elem_expr) (de_eqns p (add x (S O))) (de_eqns q (add (add x (S O)) (de_size p)))))) (S (add (de_size p) (de_size q))) *)
      rewrite app_length, Hp, Hq; auto.
    Qed.

    Fact de_size_ge_1 e : 1 <= de_size e.
    Proof. destruct e; simpl; omega. Qed.

    Fact de_eqns_vars e x : forall c, In c (de_eqns e x) -> forall y, dc_vars c y -> x <= y < x+de_size e.
    Proof.
(* Goal: forall (c : dio_constraint) (_ : @In dio_constraint c (de_eqns e x)) (y : nat) (_ : dc_vars c y), and (le x y) (lt y (add x (de_size e))) *)
      revert x; induction e as [ | | o p Hp q Hq ]; intros x; simpl; auto.
      + intros ? [ [] | [] ]; simpl; intros; omega.
      + intros ? [ [] | [] ]; simpl; intros; omega.
      + intros c [ Hc | Hc ]; [ | apply in_app_or in Hc; destruct Hc as [ Hc | Hc ] ]; subst; simpl.
        * intros; generalize (de_size_ge_1 q); intros; omega.
        * intros y Hy; apply Hp with (y := y) in Hc; simpl in *; auto; omega.
        * intros y Hy; apply Hq with (y := y) in Hc; simpl in *; auto; omega.
    Qed.

    (* If equations in de_eqns e x are satisfied in φ, then φ x must be equal to de_eval ν e *)

    Fact dc_Forall_eval φ ν e x : Forall (dc_eval φ ν) (de_eqns e x) -> de_eval ν e = φ x.
    Proof.
(* Goal: forall _ : @Forall dio_constraint (dc_eval φ ν) (de_eqns e x), @eq nat (de_eval ν e) (φ x) *)
      rewrite Forall_forall.
(* Goal: forall _ : forall (x0 : dio_constraint) (_ : @In dio_constraint x0 (de_eqns e x)), dc_eval φ ν x0, @eq nat (de_eval ν e) (φ x) *)
      revert x; induction e as [ | v| [] p Hp q Hq ]; simpl; intros x Hx; simpl; auto.
      * specialize (Hx (x,dee_nat n)); simpl in Hx; rewrite Hx; auto.
      * specialize (Hx (x,dee_par v)); simpl in Hx; rewrite Hx; auto.
      * rewrite Hp with (x+1), Hq with (x+1+de_size p).
        - symmetry; apply (Hx (_, dee_add _ _)); auto.
        - intros; apply Hx; right; apply in_or_app; auto.
        - intros; apply Hx; right; apply in_or_app; auto.
      * rewrite Hp with (x+1), Hq with (x+1+de_size p).
        - symmetry; apply (Hx (_, dee_mul _ _)); auto.
        - intros; apply Hx; right; apply in_or_app; auto.
        - intros; apply Hx; right; apply in_or_app; auto.
    Qed.

    (* Converselly, equations in de_eqns e x are satisfiable *)

    Fact dc_eval_exists_Forall ν e x : { φ | Forall (dc_eval φ ν) (de_eqns e x) }. 
    Proof.
(* Goal: @sig (forall _ : nat, nat) (fun φ : forall _ : nat, nat => @Forall dio_constraint (dc_eval φ ν) (de_eqns e x)) *)
      revert x; induction e as [ | v | o p Hp q Hq ]; simpl; intros x.
      + exists (fun  _ => n); constructor; simpl; auto.
      + exists (fun  _ => ν v); constructor; simpl; auto.
      + destruct (Hp (x+1)) as (g1 & H2).
        destruct (Hq (x+1+de_size p)) as (g2 & H4).
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add n (S (S (S O)))) (dee_comp do_add (add n (S O)) (add n (S (S (S (S O))))))) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add n (S (S (S O)))) (dee_comp do_add (add n (S (S O))) (add (add n (S (S (S (S O))))) (de_size e1)))) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr n (dee_comp do_add (add n (S O)) (add n (S (S O))))) (@app (prod nat dio_elem_expr) (de_eqns e1 (add n (S (S (S (S O)))))) (de_eqns e2 (add (add n (S (S (S (S O))))) (de_size e1)))))))) (@eq nat (φ n) O)) *)
        generalize (dc_Forall_eval _ _ H2) (dc_Forall_eval _ _ H4); intros H1 H3.
        destruct (@valuation_one_union x (do_eval o (de_eval ν p) (de_eval ν q)) (x+1,x+1+de_size p) g1 (x+1+de_size p, x+1+de_size p+de_size q) g2)
           as (g & H5 & H6 & H7).
        * simpl; rewrite Min.min_l; omega.
        * intros y; simpl; omega.
        * exists g; constructor.
          - red; unfold fst, snd; rewrite H5, H1, H3; simpl; f_equal; symmetry.
            ++ apply H6; simpl; generalize (de_size_ge_1 p); intros; omega.
            ++ apply H7; simpl; generalize (de_size_ge_1 q); intros; omega.
(* Goal: iff (or (@eq nat x (add k v)) (@ex nat (fun y : nat => and (dee_vars e y) (@eq nat x (add k y))))) (@ex nat (fun y : nat => and (@eq nat x (add k y)) (or (@eq nat y v) (dee_vars e y)))) *)
          - apply Forall_app; split.
            ++ revert H2; do 2 rewrite Forall_forall.
(* Goal: forall (_ : forall (x : dio_constraint) (_ : @In dio_constraint x (@map dio_constraint (prod nat dio_elem_expr) (dc_dec (add a n)) l)), dc_eval g f x) (x : dio_constraint) (_ : @In dio_constraint x l), dc_eval g (@dv_lift nat f (g (add a n))) x *)
               intros H c Hc.
(* Goal: dc_eval g ν c *)
               generalize (H _ Hc); apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (g x) (g1 x) *)
               intros y Hy; apply H6.
(* Goal: in_interval (@pair nat nat (add (add x (S O)) (de_size p)) (add (add (add x (S O)) (de_size p)) (de_size q))) y *)
               apply de_eqns_vars with (1 := Hc); auto.
            ++ revert H4; do 2 rewrite Forall_forall.
(* Goal: forall (_ : forall (x : dio_constraint) (_ : @In dio_constraint x (@map dio_constraint (prod nat dio_elem_expr) (dc_dec (add a n)) l)), dc_eval g f x) (x : dio_constraint) (_ : @In dio_constraint x l), dc_eval g (@dv_lift nat f (g (add a n))) x *)
               intros H c Hc.
(* Goal: dc_eval g ν c *)
               generalize (H _ Hc); apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (g x) (g2 x) *)
               intros y Hy; apply H7.
(* Goal: in_interval (@pair nat nat (add (add x (S O)) (de_size p)) (add (add (add x (S O)) (de_size p)) (de_size q))) y *)
               apply de_eqns_vars with (1 := Hc); auto.
    Qed.

    Let compare_lemma x y : { u : nat & { v | u+x = v+y } }.
    Proof.
(* Goal: @sigT nat (fun u : nat => @sig nat (fun v : nat => @eq nat (add u x) (add v y))) *)
      destruct (le_lt_dec x y).
      + exists (y-x), 0; omega.
      + exists 0, (x-y); omega.
    Qed.

    (* poly1 = poly2 <-> (eqn1 U eqn2 U { w=x+u, w=y+v, z=u+v }, z) *)

    Let g0 (n x0 x1 x2 x3 m : nat) := if le_lt_dec n m then 
                                match m - n with
                                  | 0 => x0
                                  | 1 => x1
                                  | 2 => x2
                                  | _ => x3
                                end
                              else x3.

    Let g0_0 (n x0 x1 x2 x3 : nat) : g0 n x0 x1 x2 x3 n = x0.
    Proof. 
(* Goal: @eq nat (g0 n x0 x1 x2 x3 n) x0 *)
      unfold g0; destruct (le_lt_dec n n); try omega.
      replace (n-n) with 0 by omega; auto.
    Qed.

    Let g0_1 (n x0 x1 x2 x3 : nat) : g0 n x0 x1 x2 x3 (n+1) = x1.
    Proof. 
      unfold g0; destruct (le_lt_dec n (n+1)); try omega.
      replace (n+1-n) with 1 by omega; auto.
    Qed.

    Let g0_2 (n x0 x1 x2 x3 : nat) : g0 n x0 x1 x2 x3 (n+2) = x2.
    Proof. 
      unfold g0; destruct (le_lt_dec n (n+2)); try omega.
      replace (n+2-n) with 2 by omega; auto.
    Qed.

    Let g0_3 (n x0 x1 x2 x3 : nat) : g0 n x0 x1 x2 x3 (n+3) = x3.
    Proof. 
      unfold g0; destruct (le_lt_dec n (n+3)); try omega.
      replace (n+3-n) with 3 by omega; auto.
    Qed.

    (* x1+(x2*5) at 4 ~~> v4 = v5 + v6, v5 = x1, v6 = v7 * v8, v7 = x2, v8 = 5
       x3 at 9        ~~> v9 = x3

       x1+(x2*5) = x3 at 0
                      ~~> v3 = v1 + v4, v3 = v2 + v9, v0 = v1 + v2
    *)

    Lemma dio_repr_at_eq n e1 e2 : dio_repr_at (fun ν => de_eval ν e1 = de_eval ν e2) n (4+de_size e1+de_size e2) (3+de_size e1+de_size e2).
    Proof.
      exists ((n+3, dee_add (n+1) (n+4)) ::
              (n+3, dee_add (n+2) (n+4+de_size e1)) ::
              (n,   dee_add (n+1) (n+2)) ::
              (de_eqns e1 (n+4) ++ de_eqns e2 (n+4+de_size e1))) n.
      + simpl; rewrite app_length; do 2 rewrite de_eqns_length; auto.
      + intros x c [ Hc | [ Hc | [ Hc | Hc ] ] ].
        * subst; simpl; generalize (de_size_ge_1 e2); omega.
        * subst; simpl; generalize (de_size_ge_1 e2); omega.
        * subst; simpl; generalize (de_size_ge_1 e2); omega.
        * intros Hx; apply in_app_or in Hc.
          destruct Hc as [ Hc | Hc ]; apply de_eqns_vars with (2 := Hx) in Hc;
             simpl in *; omega.
      + simpl; omega.
      + intros f.
        destruct (@dc_eval_exists_Forall f e1 (n+4)) as (g1 & H2).
        destruct (@dc_eval_exists_Forall f e2 (n+4+de_size e1)) as (g2 & H4).
        destruct (compare_lemma (g1 (n+4)) (g2 (n+4+de_size e1))) as (u & v & Huv).
        set (g3 := g0 n (u+v) u v (u+g1 (n+4))).
        destruct (@valuation_union (n+4, n+4+de_size e1) g1 (n+4+de_size e1, n+4+de_size e1+de_size e2) g2)
           as (g4 & H5 & H6).
(* Goal: and (le n n) (lt n (add n (add (add (S (S (S (S O)))) (de_size e1)) (de_size e2)))) *)
        { intro; simpl; omega. }
        destruct (@valuation_union (n,n+4) g3 (n+4,n+4+de_size e1+de_size e2) g4) 
           as (g & H7 & H8).
(* Goal: and (le n n) (lt n (add n (add (add (S (S (S (S O)))) (de_size e1)) (de_size e2)))) *)
        { intro; simpl; omega. }
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add n (S (S (S O)))) (dee_comp do_add (add n (S O)) (add n (S (S (S (S O))))))) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add n (S (S (S O)))) (dee_comp do_add (add n (S (S O))) (add (add n (S (S (S (S O))))) (de_size e1)))) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr n (dee_comp do_add (add n (S O)) (add n (S (S O))))) (@app (prod nat dio_elem_expr) (de_eqns e1 (add n (S (S (S (S O)))))) (de_eqns e2 (add (add n (S (S (S (S O))))) (de_size e1)))))))) (@eq nat (φ n) O)) *)
        generalize (de_size_ge_1 e1) (de_size_ge_1 e2); intros E1 E2.
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add n (S (S (S O)))) (dee_comp do_add (add n (S O)) (add n (S (S (S (S O))))))) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add n (S (S (S O)))) (dee_comp do_add (add n (S (S O))) (add (add n (S (S (S (S O))))) (de_size e1)))) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr n (dee_comp do_add (add n (S O)) (add n (S (S O))))) (@app (prod nat dio_elem_expr) (de_eqns e1 (add n (S (S (S (S O)))))) (de_eqns e2 (add (add n (S (S (S (S O))))) (de_size e1)))))))) (@eq nat (φ n) O)) *)
        exists g; repeat constructor; simpl.
        * rewrite H7, H7; simpl; auto; try omega.
(* Goal: @eq nat (g3 (add n (S (S (S O))))) (add (g3 (add n (S (S O)))) (g (add (add n (S (S (S (S O))))) (de_size e1)))) *)
          rewrite H8; simpl; try omega.
(* Goal: @eq nat (g3 (add n (S (S (S O))))) (add (g3 (add n (S O))) (g4 (add n (S (S (S (S O))))))) *)
          rewrite H5; simpl; try omega.
(* Goal: @eq nat (g3 (add n (S (S (S O))))) (add (g3 (add n (S O))) (g1 (add n (S (S (S (S O))))))) *)
          unfold g3; rewrite g0_1, g0_3; omega.
        * rewrite H7, H7; simpl; auto; try omega.
(* Goal: @eq nat (g3 (add n (S (S (S O))))) (add (g3 (add n (S (S O)))) (g (add (add n (S (S (S (S O))))) (de_size e1)))) *)
          rewrite H8; simpl; try omega.
(* Goal: @eq nat (g3 (add n (S (S (S O))))) (add (g3 (add n (S (S O)))) (g4 (add (add n (S (S (S (S O))))) (de_size e1)))) *)
          rewrite H6; simpl; auto; try omega.
(* Goal: @eq nat (g3 (add n (S (S (S O))))) (add (g3 (add n (S (S O)))) (g2 (add (add n (S (S (S (S O))))) (de_size e1)))) *)
          unfold g3; rewrite g0_2, g0_3; omega.
        * rewrite H7, H7, H7; simpl; try omega.
(* Goal: @eq nat (g3 n) (add (g3 (add n (S O))) (g3 (add n (S (S O))))) *)
          unfold g3; rewrite g0_0, g0_1, g0_2; auto.
        * apply Forall_app; split.
(* Goal: forall _ : @Forall dio_constraint (dc_eval φ ν) (de_eqns e x), @eq nat (de_eval ν e) (φ x) *)
          - revert H2; do 2 rewrite Forall_forall.
(* Goal: forall (_ : forall (x : dio_constraint) (_ : @In dio_constraint x (de_eqns e2 (add (add n (S (S (S (S O))))) (de_size e1)))), dc_eval g2 f x) (x : prod nat dio_elem_expr) (_ : @In (prod nat dio_elem_expr) x (de_eqns e2 (add (add n (S (S (S (S O))))) (de_size e1)))), dc_eval g f x *)
            intros H c Hc; generalize (H _ Hc).
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
            apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (g x) (g2 x) *)
            intros x Hx; rewrite H8.
            ++ apply H5, de_eqns_vars with (1 := Hc); auto.
            ++ apply de_eqns_vars with (1 := Hc) in Hx.
               simpl in *; omega.
(* Goal: forall _ : @Forall dio_constraint (dc_eval φ ν) (de_eqns e x), @eq nat (de_eval ν e) (φ x) *)
          - revert H4; do 2 rewrite Forall_forall.
(* Goal: forall (_ : forall (x : dio_constraint) (_ : @In dio_constraint x (de_eqns e2 (add (add n (S (S (S (S O))))) (de_size e1)))), dc_eval g2 f x) (x : prod nat dio_elem_expr) (_ : @In (prod nat dio_elem_expr) x (de_eqns e2 (add (add n (S (S (S (S O))))) (de_size e1)))), dc_eval g f x *)
            intros H c Hc; generalize (H _ Hc).
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
            apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (g x) (g2 x) *)
            intros x Hx; rewrite H8.
            ++ apply H6, de_eqns_vars with (1 := Hc); auto.
            ++ apply de_eqns_vars with (1 := Hc) in Hx.
               simpl in *; omega.
      + intros f; split.
        * intros Hf.
          destruct (@dc_eval_exists_Forall f e1 (n+4)) as (g1 & H2).
          destruct (@dc_eval_exists_Forall f e2 (n+4+de_size e1)) as (g2 & H4).
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add n (S (S (S O)))) (dee_comp do_add (add n (S O)) (add n (S (S (S (S O))))))) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add n (S (S (S O)))) (dee_comp do_add (add n (S (S O))) (add (add n (S (S (S (S O))))) (de_size e1)))) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr n (dee_comp do_add (add n (S O)) (add n (S (S O))))) (@app (prod nat dio_elem_expr) (de_eqns e1 (add n (S (S (S (S O)))))) (de_eqns e2 (add (add n (S (S (S (S O))))) (de_size e1)))))))) (@eq nat (φ n) O)) *)
          generalize (dc_Forall_eval _ _ H2) (dc_Forall_eval _ _ H4); intros H1 H3.
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add n (S (S (S O)))) (dee_comp do_add (add n (S O)) (add n (S (S (S (S O))))))) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add n (S (S (S O)))) (dee_comp do_add (add n (S (S O))) (add (add n (S (S (S (S O))))) (de_size e1)))) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr n (dee_comp do_add (add n (S O)) (add n (S (S O))))) (@app (prod nat dio_elem_expr) (de_eqns e1 (add n (S (S (S (S O)))))) (de_eqns e2 (add (add n (S (S (S (S O))))) (de_size e1)))))))) (@eq nat (φ n) O)) *)
          set (g3 := g0 n 0 0 0 (de_eval f e1)).
          destruct (@valuation_union (n+4, n+4+de_size e1) g1 (n+4+de_size e1, n+4+de_size e1+de_size e2) g2)
             as (g4 & H5 & H6).
(* Goal: and (le n n) (lt n (add n (add (add (S (S (S (S O)))) (de_size e1)) (de_size e2)))) *)
          { intro; simpl; omega. }
          destruct (@valuation_union (n, n+4) g3 (n+4, n+4+de_size e1+de_size e2) g4) 
            as (g & H7 & H8).
(* Goal: and (le n n) (lt n (add n (add (add (S (S (S (S O)))) (de_size e1)) (de_size e2)))) *)
          { intro; simpl; omega. }
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add n (S (S (S O)))) (dee_comp do_add (add n (S O)) (add n (S (S (S (S O))))))) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add n (S (S (S O)))) (dee_comp do_add (add n (S (S O))) (add (add n (S (S (S (S O))))) (de_size e1)))) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr n (dee_comp do_add (add n (S O)) (add n (S (S O))))) (@app (prod nat dio_elem_expr) (de_eqns e1 (add n (S (S (S (S O)))))) (de_eqns e2 (add (add n (S (S (S (S O))))) (de_size e1)))))))) (@eq nat (φ n) O)) *)
          generalize (de_size_ge_1 e1) (de_size_ge_1 e2); intros E1 E2.
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add n (S (S (S O)))) (dee_comp do_add (add n (S O)) (add n (S (S (S (S O))))))) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add n (S (S (S O)))) (dee_comp do_add (add n (S (S O))) (add (add n (S (S (S (S O))))) (de_size e1)))) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr n (dee_comp do_add (add n (S O)) (add n (S (S O))))) (@app (prod nat dio_elem_expr) (de_eqns e1 (add n (S (S (S (S O)))))) (de_eqns e2 (add (add n (S (S (S (S O))))) (de_size e1)))))))) (@eq nat (φ n) O)) *)
          exists g; repeat constructor; simpl.
          - rewrite H7, H7; simpl; auto; try omega.
(* Goal: @eq nat (g3 (add n (S (S (S O))))) (add (g3 (add n (S (S O)))) (g (add (add n (S (S (S (S O))))) (de_size e1)))) *)
            rewrite H8; simpl; try omega.
(* Goal: @eq nat (g3 (add n (S (S (S O))))) (add (g3 (add n (S O))) (g4 (add n (S (S (S (S O))))))) *)
            rewrite H5; simpl; try omega.
(* Goal: @eq nat (g3 (add n (S (S (S O))))) (add (g3 (add n (S O))) (g1 (add n (S (S (S (S O))))))) *)
            unfold g3; rewrite g0_3, g0_1; omega.
          - rewrite H7, H7; simpl; auto; try omega.
(* Goal: @eq nat (g3 (add n (S (S (S O))))) (add (g3 (add n (S (S O)))) (g (add (add n (S (S (S (S O))))) (de_size e1)))) *)
            rewrite H8; simpl; try omega.
(* Goal: @eq nat (g3 (add n (S (S (S O))))) (add (g3 (add n (S (S O)))) (g4 (add (add n (S (S (S (S O))))) (de_size e1)))) *)
            unfold g3; rewrite g0_3, g0_2.
(* Goal: @eq nat (de_eval f e1) (add O (g4 (add (add n (S (S (S (S O))))) (de_size e1)))) *)
            rewrite Hf, H6; simpl; auto; omega.
          - rewrite H7, H7, H7; simpl; try omega.
(* Goal: @eq nat (g3 n) (add (g3 (add n (S O))) (g3 (add n (S (S O))))) *)
            unfold g3; rewrite g0_0, g0_1, g0_2; auto.
(* Goal: iff (or (@eq nat x (add k v)) (@ex nat (fun y : nat => and (dee_vars e y) (@eq nat x (add k y))))) (@ex nat (fun y : nat => and (@eq nat x (add k y)) (or (@eq nat y v) (dee_vars e y)))) *)
          - apply Forall_app; split.
            ++ revert H2; do 2 rewrite Forall_forall.
(* Goal: forall (_ : forall (x : dio_constraint) (_ : @In dio_constraint x (de_eqns e2 (add (add n (S (S (S (S O))))) (de_size e1)))), dc_eval g2 f x) (x : prod nat dio_elem_expr) (_ : @In (prod nat dio_elem_expr) x (de_eqns e2 (add (add n (S (S (S (S O))))) (de_size e1)))), dc_eval g f x *)
               intros H c Hc; generalize (H _ Hc).
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
               apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (g x) (g2 x) *)
               intros x Hx; rewrite H8.
               ** apply H5, de_eqns_vars with (1 := Hc); auto.
               ** apply de_eqns_vars with (1 := Hc) in Hx.
                  simpl in *; omega.
            ++ revert H4; do 2 rewrite Forall_forall.
(* Goal: forall (_ : forall (x : dio_constraint) (_ : @In dio_constraint x (de_eqns e2 (add (add n (S (S (S (S O))))) (de_size e1)))), dc_eval g2 f x) (x : prod nat dio_elem_expr) (_ : @In (prod nat dio_elem_expr) x (de_eqns e2 (add (add n (S (S (S (S O))))) (de_size e1)))), dc_eval g f x *)
               intros H c Hc; generalize (H _ Hc).
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
               apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (g x) (g2 x) *)
               intros x Hx; rewrite H8.
               ** apply H6, de_eqns_vars with (1 := Hc); auto.
               ** apply de_eqns_vars with (1 := Hc) in Hx.
                  simpl in *; omega.
          - rewrite H7; simpl; try omega.
(* Goal: @eq nat (g3 n) O *)
            unfold g3; rewrite g0_0; auto.
        * intros (g & H1 & H0).
(* Goal: @eq nat (de_eval f e1) (de_eval f e2) *)
          do 3 rewrite Forall_cons_inv in H1.
(* Goal: @eq nat (de_eval f e1) (de_eval f e2) *)
          rewrite Forall_app in H1.
(* Goal: @eq nat (de_eval f e1) (de_eval f e2) *)
          destruct H1 as (H1 & H2 & H3 & H4 & H5).
          simpl in *.
(* Goal: @eq nat (de_eval f e1) (de_eval f e2) *)
          rewrite dc_Forall_eval with (1 := H4).
(* Goal: @eq nat (g (add n (S (S (S (S O)))))) (de_eval f e2) *)
          rewrite dc_Forall_eval with (1 := H5).
(* Goal: and (le a r) (lt r (add a (add n (S O)))) *)
          omega.
    Defined.

  End diophantine_sys_expr.

  Let not_interval_union a1 n1 a2 n2 : 
           a1+n1 <= a2
        -> ~ in_interval (interval_union (a1, a1 + n1) (a2, a2 + n2)) (a2 + n2).
  Proof.
(* Goal: forall _ : le (add a1 n1) a2, not (in_interval (interval_union (@pair nat nat a1 (add a1 n1)) (@pair nat nat a2 (add a2 n2))) (add a2 n2)) *)
    simpl; intros H1 (_ & H3).
(* Goal: and (le a r) (lt r (add a (add n (S O)))) *)
    rewrite Nat.max_r in H3; omega.
  Qed.

  Lemma dio_repr_at_conj R1 a1 n1 p1 R2 a2 n2 p2 n : 
          dio_repr_at R1 a1 n1 p1
       -> dio_repr_at R2 a2 n2 p2
       -> a1+n1 <= a2
       -> n = 1+a2+n2-a1
       -> dio_repr_at (fun ν => R1 ν /\ R2 ν) a1 n (1+p1+p2).
  Proof.
(* Goal: forall (_ : dio_repr_at R1 a1 n1 p1) (_ : dio_repr_at R2 a2 n2 p2) (_ : le (add a1 n1) a2) (_ : @eq nat n (sub (add (add (S O) a2) n2) a1)), dio_repr_at (fun ν : forall _ : nat, nat => or (R1 ν) (R2 ν)) a1 n (add (add (S O) p1) p2) *)
    intros [ l1 r1 F0 F1 F2 F3 F4 ] [ l2 r2 G0 G1 G2 G3 G4 ] H12 ?; subst n.
    exists ((a2+n2,dee_add r1 r2)::l1++l2) (a2+n2).
    + simpl; rewrite app_length, F0, G0; omega.
    + replace (a1+(1+a2+n2-a1)) with (1+a2+n2) by omega.
(* Goal: forall (x : nat) (c : dio_constraint) (_ : @In dio_constraint c (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2))) (_ : dc_vars c x), and (le a1 x) (lt x (add (add (S O) a2) n2)) *)
      intros x c [ Hc | Hc ].
      * subst; simpl; omega.
      * intros H1; apply in_app_or in Hc; destruct Hc as [ Hc | Hc ].
        - specialize (F1 _ _ Hc H1); omega.
        - specialize (G1 _ _ Hc H1); omega.
    + omega.
    + intros f.
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => @Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2))) *)
      destruct (F3 f) as (g1 & H1).
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => @Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2))) *)
      destruct (G3 f) as (g2 & H2).
      destruct (@valuation_one_union (a2+n2) (g1 r1+g2 r2) (a1,a1+n1) g1 (a2,a2+n2) g2) 
        as (g & Hg1 & Hg2 & Hg3); auto.
(* Goal: interval_disjoint (@pair nat nat a1 (add a1 n1)) (@pair nat nat a2 (add a2 n2)) *)
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2))) (@eq nat (φ (add a2 n2)) O)) *)
      { red; simpl; intros; omega. }
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => @Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2))) *)
      exists g; constructor; [ | apply Forall_app; split ].
      * simpl; rewrite (Hg2 r1), (Hg3 r2); auto.
      * apply Forall_impl with (2 := H1).
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
        intros c Hc; apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (g x) (g1 x) *)
        intros x Hx; apply Hg2, F1 with c; auto.
      * apply Forall_impl with (2 := H2).
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
        intros c Hc; apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (g x) (g2 x) *)
        intros x Hx; apply Hg3, G1 with c; auto.
    + intros f; rewrite F4, G4; split.
      * intros ((g1 & H1 & H2) & (g2 & H3 & H4)).
        destruct (@valuation_one_union (a2+n2) 0 (a1,a1+n1) g1 (a2,a2+n2) g2) 
          as (g & Hg1 & Hg2 & Hg3); auto.
(* Goal: interval_disjoint (@pair nat nat a1 (add a1 n1)) (@pair nat nat a2 (add a2 n2)) *)
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2))) (@eq nat (φ (add a2 n2)) O)) *)
        { red; simpl; intros; omega. }
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_add r1 r2)) (@app dio_constraint l1 l2))) (@eq nat (φ (add a2 n2)) O)) *)
        exists g; split; auto; constructor; simpl.
        ++ rewrite Hg1, Hg2, Hg3; auto; omega.
        ++ apply Forall_app; split.
           ** apply Forall_impl with (2 := H1).
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
              intros c Hc; apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (g x) (g1 x) *)
              intros x Hx; apply Hg2, F1 with c; auto.
           ** apply Forall_impl with (2 := H3).
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
              intros c Hc; apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (g x) (g2 x) *)
              intros x Hx; apply Hg3, G1 with c; auto.
      * intros (g & Hg1 & Hg2).
(* Goal: or (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) l1) (@eq nat (φ r1) O))) (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) l2) (@eq nat (φ r2) O))) *)
        inversion Hg1 as [ | ? ? Hg3 Hg4 ].
(* Goal: or (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) l1) (@eq nat (φ r1) O))) (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) l2) (@eq nat (φ r2) O))) *)
        apply Forall_app in Hg4; destruct Hg4 as (Hg4 & Hg5).
(* Goal: and (le a r) (lt r (add a (add n (S O)))) *)
        simpl in Hg3; split; exists g; split; auto; omega.
  Defined.

  Lemma dio_repr_at_disj R1 a1 n1 p1 R2 a2 n2 p2 n : 
          dio_repr_at R1 a1 n1 p1
       -> dio_repr_at R2 a2 n2 p2
       -> a1+n1 <= a2
       -> n = 1+a2+n2-a1
       -> dio_repr_at (fun ν => R1 ν \/ R2 ν) a1 n (1+p1+p2). 
  Proof.
(* Goal: forall (_ : dio_repr_at R1 a1 n1 p1) (_ : dio_repr_at R2 a2 n2 p2) (_ : le (add a1 n1) a2) (_ : @eq nat n (sub (add (add (S O) a2) n2) a1)), dio_repr_at (fun ν : forall _ : nat, nat => or (R1 ν) (R2 ν)) a1 n (add (add (S O) p1) p2) *)
    intros [ l1 r1 F0 F1 F2 F3 F4 ] [ l2 r2 G0 G1 G2 G3 G4 ] H12 ?; subst n.
    exists ((a2+n2,dee_mul r1 r2)::l1++l2) (a2+n2).
    + simpl; rewrite app_length, F0, G0; omega.
    + replace (a1+(1+a2+n2-a1)) with (1+a2+n2) by omega.
(* Goal: forall (x : nat) (c : dio_constraint) (_ : @In dio_constraint c (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2))) (_ : dc_vars c x), and (le a1 x) (lt x (add (add (S O) a2) n2)) *)
      intros x c [ Hc | Hc ].
      * subst; simpl; omega.
      * intros H1; apply in_app_or in Hc; destruct Hc as [ Hc | Hc ].
        - specialize (F1 _ _ Hc H1); omega.
        - specialize (G1 _ _ Hc H1); omega.
    + omega.
    + intros f.
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => @Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2))) *)
      destruct (F3 f) as (g1 & H1).
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => @Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2))) *)
      destruct (G3 f) as (g2 & H2).
      destruct (@valuation_one_union (a2+n2) (g1 r1*g2 r2) (a1,a1+n1) g1 (a2,a2+n2) g2) 
        as (g & Hg1 & Hg2 & Hg3); auto.
(* Goal: interval_disjoint (@pair nat nat a1 (add a1 n1)) (@pair nat nat a2 (add a2 n2)) *)
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2))) (@eq nat (φ (add a2 n2)) O)) *)
      { red; simpl; intros; omega. }
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => @Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2))) *)
      exists g; constructor; [ | apply Forall_app; split ].
      * simpl; rewrite (Hg2 r1), (Hg3 r2); auto.
      * apply Forall_impl with (2 := H1).
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
        intros c Hc; apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (g x) (g1 x) *)
        intros x Hx; apply Hg2, F1 with c; auto.
      * apply Forall_impl with (2 := H2).
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
        intros c Hc; apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (g x) (g2 x) *)
        intros x Hx; apply Hg3, G1 with c; auto.
    + intros f; rewrite F4, G4; split.
      * intros [ (g1 & H1 & H2) | (g2 & H1 & H2) ].
        - destruct (G3 f) as (g2 & H3).
          destruct (@valuation_one_union (a2+n2) 0 (a1,a1+n1) g1 (a2,a2+n2) g2) 
            as (g & Hg1 & Hg2 & Hg3); auto.
(* Goal: interval_disjoint (@pair nat nat a1 (add a1 n1)) (@pair nat nat a2 (add a2 n2)) *)
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2))) (@eq nat (φ (add a2 n2)) O)) *)
          { red; simpl; intros; omega. }
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ (@dv_lift nat f (g (add a n)))) l) (@eq nat (φ r) O)) *)
          exists g; split; auto.
(* Goal: @Forall dio_constraint (dc_eval g f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2)) *)
          constructor; simpl; [ | apply Forall_app; split ].
          ++ rewrite Hg1, Hg2, H2; auto.
          ++ apply Forall_impl with (2 := H1).
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
             intros c Hc; apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (g x) (g1 x) *)
             intros x Hx; apply Hg2, F1 with c; auto.
          ++ apply Forall_impl with (2 := H3).
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
             intros c Hc; apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (g x) (g2 x) *)
             intros x Hx; apply Hg3, G1 with c; auto.
        - destruct (F3 f) as (g1 & H3).
          destruct (@valuation_one_union (a2+n2) 0 (a1,a1+n1) g1 (a2,a2+n2) g2) 
            as (g & Hg1 & Hg2 & Hg3); auto.
(* Goal: interval_disjoint (@pair nat nat a1 (add a1 n1)) (@pair nat nat a2 (add a2 n2)) *)
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2))) (@eq nat (φ (add a2 n2)) O)) *)
          { red; simpl; intros; omega. }
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ (@dv_lift nat f (g (add a n)))) l) (@eq nat (φ r) O)) *)
          exists g; split; auto.
(* Goal: @Forall dio_constraint (dc_eval g f) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr (add a2 n2) (dee_comp do_mul r1 r2)) (@app dio_constraint l1 l2)) *)
          constructor; simpl; [ | apply Forall_app; split ].
          ++ rewrite Hg1, (Hg3 r2), H2, mult_comm; auto.
          ++ apply Forall_impl with (2 := H3).
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
             intros c Hc; apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (g x) (g1 x) *)
             intros x Hx; apply Hg2, F1 with c; auto.
          ++ apply Forall_impl with (2 := H1).
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
             intros c Hc; apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (g x) (g2 x) *)
             intros x Hx; apply Hg3, G1 with c; auto.
      * intros (g & Hg1 & Hg2).
(* Goal: or (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) l1) (@eq nat (φ r1) O))) (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) l2) (@eq nat (φ r2) O))) *)
        inversion Hg1 as [ | ? ? Hg3 Hg4 ].
(* Goal: or (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) l1) (@eq nat (φ r1) O))) (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) l2) (@eq nat (φ r2) O))) *)
        apply Forall_app in Hg4; destruct Hg4 as (Hg4 & Hg5).
(* Goal: or (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) l1) (@eq nat (φ r1) O))) (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) l2) (@eq nat (φ r2) O))) *)
        simpl in Hg3; rewrite Hg2 in Hg3.
(* Goal: or (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) l1) (@eq nat (φ r1) O))) (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) l2) (@eq nat (φ r2) O))) *)
        symmetry in Hg3; apply mult_is_O in Hg3.
(* Goal: or (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) l1) (@eq nat (φ r1) O))) (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) l2) (@eq nat (φ r2) O))) *)
        destruct Hg3 as [ Hg3 | Hg3 ]; [ left | right ]; exists g; auto.
  Defined.

  Lemma dio_repr_at_exst R a n m p : 
          dio_repr_at R a n p
       -> m = n+1
       -> dio_repr_at (fun ν => exists n, R (dv_lift ν n)) a m p. 
  Proof.
(* Goal: forall (_ : dio_repr_at R a n p) (_ : @eq nat m (add n (S O))), dio_repr_at (fun ν : forall _ : nat, nat => @ex nat (fun n : nat => R (@dv_lift nat ν n))) a m p *)
    intros [ l r F0 F1 F2 F3 F4 ] ?; subst m.
    exists (map (dc_dec (a+n)) l) r.
    + rewrite map_length; auto.
    + intros x c'; rewrite in_map_iff.
(* Goal: forall (_ : @ex dio_constraint (fun x : dio_constraint => and (@eq dio_constraint (dc_dec (add a n) x) c') (@In dio_constraint x l))) (_ : dc_vars c' x), and (le a x) (lt x (add a (add n (S O)))) *)
      intros (c & E & Hc) H; subst.
(* Goal: and (le a x) (lt x (add a (add n (S O)))) *)
      apply dc_vars_dec in H.
(* Goal: and (le a r) (lt r (add a (add n (S O)))) *)
      destruct H as [ | H ]; subst; simpl; try omega.
      apply F1 in H; simpl in *; auto; omega.
    + omega.
    + intros f.
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => @Forall dio_constraint (dc_eval φ f) (@map dio_constraint (prod nat dio_elem_expr) (dc_dec (add a n)) l)) *)
      destruct (F3 (fun x => match x with 0 => 0 | S x => f x end)) as (g & Hg).
      exists (fun x => if eq_nat_dec x (a+n) then 0 else g x).
(* Goal: @Forall dio_constraint (dc_eval (fun x : nat => if Nat.eq_dec x (add a n) then u else g x) f) (@map dio_constraint (prod nat dio_elem_expr) (dc_dec (add a n)) l) *)
      rewrite Forall_map.
(* Goal: @Forall dio_constraint (fun x : dio_constraint => dc_eval (fun x0 : nat => if Nat.eq_dec x0 (add a n) then O else g x0) f (dc_dec (add a n) x)) l *)
      apply Forall_impl with (2 := Hg). 
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
      intros c Hc; rewrite dc_eval_dec; apply dc_eval_ext; auto.
(* Goal: forall (x : nat) (_ : dc_vars c x), @eq nat (if Nat.eq_dec x (add a n) then u else g x) (g x) *)
      * intros x Hx.
        destruct (eq_nat_dec x (a+n)); subst; auto.
(* Goal: and (le a r) (lt r (add a (add n (S O)))) *)
        apply F1 in Hx; auto; omega.
      * intros [ | x ]; auto.
        destruct (eq_nat_dec (a+n) (a+n)); tauto.
    + intros f; split.
      * intros (u & Hu).
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@map dio_constraint (prod nat dio_elem_expr) (dc_dec (add a n)) l)) (@eq nat (φ r) O)) *)
        apply F4 in Hu.
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ f) (@map dio_constraint (prod nat dio_elem_expr) (dc_dec (add a n)) l)) (@eq nat (φ r) O)) *)
        destruct Hu as (g & H1 & H2).
        exists (fun x => if eq_nat_dec x (a+n) then u else g x); simpl; split.
        - rewrite Forall_map.
(* Goal: @Forall dio_constraint (fun x : dio_constraint => dc_eval (fun x0 : nat => if Nat.eq_dec x0 (add a n) then u else g x0) f (dc_dec (add a n) x)) l *)
          apply Forall_impl with (2 := H1).
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
          intros c Hc; rewrite dc_eval_dec; apply dc_eval_ext; auto.
          ++ intros x Hx.
             destruct (eq_nat_dec x (a+n)); auto.
(* Goal: and (le a r) (lt r (add a (add n (S O)))) *)
             subst x; apply F1 in Hx; auto; omega.
          ++ intros [ | x ]; auto.
             destruct (eq_nat_dec (a+n) (a+n)); tauto.
        - destruct (eq_nat_dec r (a+n)); auto.
(* Goal: and (le a r) (lt r (add a (add n (S O)))) *)
          subst; omega.
      * intros (g & H1 & H2).
        exists (g (a+n)); rewrite F4.
(* Goal: @ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ (@dv_lift nat f (g (add a n)))) l) (@eq nat (φ r) O)) *)
        exists g; split; auto.
(* Goal: forall _ : @Forall dio_constraint (dc_eval φ ν) (de_eqns e x), @eq nat (de_eval ν e) (φ x) *)
        revert H1; do 2 rewrite Forall_forall.
(* Goal: forall (_ : forall (x : dio_constraint) (_ : @In dio_constraint x (@map dio_constraint (prod nat dio_elem_expr) (dc_dec (add a n)) l)), dc_eval g f x) (x : dio_constraint) (_ : @In dio_constraint x l), dc_eval g (@dv_lift nat f (g (add a n))) x *)
        intros H c Hc.
(* Goal: dc_eval g (@dv_lift nat f (g (add a n))) c *)
        apply in_map with (f := dc_dec _), H in Hc.
(* Goal: forall _ : dc_eval g2 f c, dc_eval g f c *)
        revert Hc; rewrite dc_eval_dec; apply dc_eval_ext; auto.
  Defined.

  Fixpoint df_weight_1 f :=
    match f with
      | df_atm a b  => 4 + de_size a + de_size b
      | df_conj f g => 1 + df_weight_1 f + df_weight_1 g  
      | df_disj f g => 1 + df_weight_1 f + df_weight_1 g  
      | df_exst f   => 1 + df_weight_1 f
    end.

  Fact df_weigth_1_size f : df_weight_1 f <= 4*df_size f.
  Proof. induction f; simpl; omega. Qed.

  Fixpoint df_weight_2 f :=
    match f with
      | df_atm a b  => 3 + de_size a + de_size b
      | df_conj f g => 1 + df_weight_2 f + df_weight_2 g  
      | df_disj f g => 1 + df_weight_2 f + df_weight_2 g  
      | df_exst f   => df_weight_2 f
    end.

  Fact df_weigth_2_size f : df_weight_2 f <= 3*df_size f.
  Proof. induction f; simpl in *; omega. Qed.

  Lemma dio_repr_at_form n f : dio_repr_at (df_pred f) n (df_weight_1 f) (df_weight_2 f).
  Proof.
    revert n;
    induction f as [ a b | f IHf g IHg | f IHf g IHg | f IHf ]; intros n; simpl df_pred; simpl df_weight_1; simpl df_weight_2.
    + apply dio_repr_at_eq.
    + apply dio_repr_at_conj with (n1 := df_weight_1 f) (a2 := n+df_weight_1 f) (n2 := df_weight_1 g); auto; omega.
    + apply dio_repr_at_disj with (n1 := df_weight_1 f) (a2 := n+df_weight_1 f) (n2 := df_weight_1 g); auto; omega.
    + apply dio_repr_at_exst with (n := df_weight_1 f); auto; omega.
  Defined.

  (** For any diophantine logic formula f of size s, one can compute a list l 
      of at most 1+3*s elementary diophantine constraints, containing at 
      most 4*s variables and such that df_pred f ν is equivalent to 
      the simultaneous satisfiability at ν of all the elementary constraints in l *)

  Theorem dio_formula_elem f : { l | length l <= 1+3*df_size f
                                 /\ (forall c x, In c l -> dc_vars c x -> x < 4*df_size f)  
                                 /\  forall ν, df_pred f ν <-> exists φ, Forall (dc_eval φ ν) l }.
  Proof.
(* Goal: @sig (list dio_constraint) (fun l : list dio_constraint => and (le (@length dio_constraint l) (add (S O) (mul (S (S (S O))) (df_size f)))) (and (forall (c : dio_constraint) (x : nat) (_ : @In dio_constraint c l) (_ : dc_vars c x), lt x (mul (S (S (S (S O)))) (df_size f))) (forall ν : forall _ : nat, nat, iff (df_pred f ν) (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => @Forall dio_constraint (dc_eval φ ν) l))))) *)
    destruct (dio_repr_at_form 0 f) as [l r H0 H1 H2 H3 H4].
(* Goal: and (le a r) (lt r (add a (add n (S O)))) *)
    exists ((r,dee_nat 0) :: l); split; [ | split ]; simpl length; try omega.
    + rewrite H0; apply le_n_S, df_weigth_2_size.
    + intros c x [ [] | H ].
      * simpl dc_vars; intros [ | [] ]; subst.
(* Goal: and (le a r) (lt r (add a (add n (S O)))) *)
        generalize (df_weigth_1_size f); intros; omega.
      * intros G; apply H1 in G; auto.
(* Goal: and (le a r) (lt r (add a (add n (S O)))) *)
        generalize (df_weigth_1_size f); intros; omega.
    + intros ν; rewrite H4.
(* Goal: iff (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => and (@Forall dio_constraint (dc_eval φ ν) l) (@eq nat (φ r) O))) (@ex (forall _ : nat, nat) (fun φ : forall _ : nat, nat => @Forall dio_constraint (dc_eval φ ν) (@cons (prod nat dio_elem_expr) (@pair nat dio_elem_expr r (dee_nat O)) l))) *)
      split; intros (φ & H); exists φ; revert H; rewrite Forall_cons_inv; simpl; tauto.
  Defined.

  Definition dio_fs f := proj1_sig (dio_formula_elem f).
                 
End diophantine_system.

(* Check dio_formula_elem.
Print Assumptions dio_formula_elem. *)
