Local Notation "∑" := (msum plus 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.Fact convex_neq a b x y : a < b -> a*x+b*y = a*y+b*x -> x = y.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.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.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.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.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.Fact dp_eval_fix_mul φ ν p q : dp_eval φ ν (dp_mul p q) = dp_eval φ ν p * dp_eval φ ν q.Fixpoint dp_size p :=
    match p with
      | dp_nat n => 1
      | dp_var v => 1
      | dp_par i => 1
      | dp_comp _ p q => 1 + dp_size p + dp_size q 
    end.Fact dp_size_fix_comp o p q : dp_size (dp_comp o p q) = 1 + dp_size p + dp_size q.Definition dio_single := (dio_polynomial * dio_polynomial)%type.Definition dio_single_size (e : dio_single) := dp_size (fst e) + dp_size (snd e).Definition dio_single_pred e ν := exists φ, dp_eval φ ν (fst e) = dp_eval φ ν (snd e).

(* 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 }.
Theorem dio_elem_equation l : { E : dio_single nat nat | dio_single_size E <= 2+20*length l /\ forall ν, dio_single_pred E ν <-> exists φ, Forall (dc_eval φ ν) l }.