Section diophantine_polynomial.
Variable (V P : Set).
Inductive dio_polynomial : Set :=
| dp_nat : nat -> dio_polynomial                  (* natural number constant *)
| dp_var : V   -> dio_polynomial                  (* existentially quantified variable *)
| dp_par : P   -> dio_polynomial                  (* parameter *)
| dp_comp : dio_op -> dio_polynomial -> dio_polynomial -> dio_polynomial.
Notation dp_add := (dp_comp do_add).
Notation dp_mul := (dp_comp do_mul).
Fixpoint dp_var_list p :=
match p with
| dp_nat _      => nil
| dp_var v      => v::nil
| dp_par _      => nil
| dp_comp _ p q => dp_var_list p ++ dp_var_list q
end.
Fixpoint dp_par_list p :=
match p with
| dp_nat _      => nil
| dp_var _      => nil
| dp_par x      => x::nil
| dp_comp _ p q => dp_par_list p ++ dp_par_list q
end.
(* ρ σ ν φ *)
Fixpoint dp_eval φ ν p :=
match p with
| dp_nat n => n
| dp_var v => φ v
| dp_par i => ν i
| dp_comp do_add p q => dp_eval φ ν p + dp_eval φ ν q
| dp_comp do_mul p q => dp_eval φ ν p * dp_eval φ ν q
end.
Fact dp_eval_ext φ ν φ' ν' p :
(forall v, In v (dp_var_list p) -> φ v = φ' v)
-> (forall i, In i (dp_par_list p) -> ν i = ν' i)
-> dp_eval φ ν p = dp_eval φ' ν' p.
Fact dp_eval_fix_add φ ν p q : dp_eval φ ν (dp_add p q) = dp_eval φ ν p + dp_eval φ ν q.
Let dee2dp_2_size l : dp_size (dee2dp_2 l) <= 1+12*length l.
Let dc_value_1 φ ν (c : dio_constraint) := 2*(φ (fst c)*dee_eval φ ν (snd c)).
Let dc_value_2 φ ν (c : dio_constraint) := (φ (fst c)*φ (fst c)) + (dee_eval φ ν (snd c)*dee_eval φ ν (snd c)).
Let dee2dp_1_eval φ ν l : dp_eval φ ν (dee2dp_1 l) = fold_right plus 0 (map (dc_value_1 φ ν) l).
Let dee2dp_2_eval φ ν l : dp_eval φ ν (dee2dp_2 l) = fold_right plus 0 (map (dc_value_2 φ ν) l).
Let dee2dp_spec φ ν l : dp_eval φ ν (dee2dp_1 l) = dp_eval φ ν (dee2dp_2 l)
<-> Forall (dc_eval φ ν) l.

Theorem dio_elem_single l : { E : dio_single nat nat | dio_single_size E <= 2+20*length l
/\ forall ν φ, dp_eval φ ν (fst E) = dp_eval φ ν (snd E) <-> Forall (dc_eval φ ν) l }.