(** * Polymax Bounding

  - The lemma [polymax_bounding] states that the output of an expression [e] with [n] normal variables
    is bounded by the sum of the polynomial [poly_BC n e] and of the size of its longest safe input.
*)

Fixpoint poly_BC n (e : BC) : pol :=
  match e with 
    | zero => pcst 0 0
    | proj n s i => if (leb (S i) n) then pproj n i else (pcst n 0)
    | succ b => pcst 0 1
    | pred => pcst 0 0
    | cond => pcst 0 0
    | rec g h0 h1 =>
        pplus (pshift (poly_BC (n - 1) g)) 
        (pmult (pproj n 0) (pplus (poly_BC n h0) (poly_BC n h1)))
    | comp n s h rl tl =>
      (pplus (pcst n 0)
        (pplus (pcomp (poly_BC (length rl) h) (map (poly_BC n) rl ))
          (pplusl (map (poly_BC n) tl))))
  end.

(* Specifications: *)
Lemma arity_poly_BC : forall e n s, arities e = ok_arities n s -> parity (poly_BC n e) = n.
Lemma pWF_poly_BC : forall e n s, arities e = ok_arities n s -> pWF (poly_BC n e).
Lemma polymax_bounding : forall (e : BC) xl yl n s, arities e = ok_arities n s -> length (sem e xl yl) <= peval (poly_BC n e) (map (@length _) xl) + maxl (map (@length _) yl).
Lemma proj_seq_shift_safe : forall n m ln ls d, map (fun x : BC => sem x ln (d :: ls)) (map (proj n (S m)) (seq (S n) m)) = map (fun x : BC => sem x ln ls) (map (proj n m) (seq n m)).
Lemma proj_seq_shift_normal : forall n ln ls d, map (fun x : BC => sem x (d :: ln) ls) (map (proj (S n) 0) (seq 1 n)) = map (fun x : BC => sem x ln ls) (map (proj n 0) (seq 0 n)).