(**************************************************************)
(*   Copyright Dominique Larchey-Wendling [*]                 *)
(*                                                            *)
(*                             [*] Affiliation LORIA -- CNRS  *)
(**************************************************************)
(*      This file is distributed under the terms of the       *)
(*         CeCILL v2 FREE SOFTWARE LICENSE AGREEMENT          *)
(**************************************************************)
(** ** Single Diophantine equations *)
Set Implicit Arguments.
Local Notation "∑" := (msum plus 0).
Section convexity.
Let convex_1 x p : 2*(x*(x+p)) <= x*x+(x+p)*(x+p).
Let convex_2 x p : 2*(x*(x+p)) = x*x+(x+p)*(x+p) -> p = 0.
Fact convex_le x y : 2*(x*y) <= x*x+y*y.
Fact convex_eq x y : 2*(x*y) = x*x+y*y -> x = y.
Let convex_3 a t x y : 0 < t -> a*x+(a+t)*y = a*y+(a+t)*x -> x = y.
Fact convex_neq a b x y : a < b -> a*x+b*y = a*y+b*x -> x = y.
Hint Resolve convex_le.
Fact convex_n_le n (f g : nat -> nat) :  ∑ n (fun i => 2*(f i*g i))
<= ∑ n (fun i => f i*f i + g i*g i).
Hint Resolve convex_n_le.
Let nat_le_sum a b c d : a <= b -> c <= d -> a+c = b+d -> a = b /\ c = d.
End convexity.
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.

(* Specifications: *)
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 }.