(*****************************************************************************************)
(*                  QI of function symbols / terms                                       *)
(*****************************************************************************************)

(* c'est cette forme qui est utilisée partout *)
Definition subterm (qif:assignment_function) := forall f l x, In x l -> x <= qif f l.(*monotonicity*)
Definition monotonicity_qif (qif:assignment_function) :=
  forall f lx ly, Forall2 le lx ly -> qif f lx <= qif f ly.(* assignment of a term*)
Fixpoint term_assignment (qic:assignment_constructor) (qif:assignment_function)
(t:term) {struct t}:=
   match t with
  | var v=> 0 (* pas necessaire. Les QI sont toujours appliquées sur des termes clots. *)
  | capply c lt => qic c (map (term_assignment qic qif) lt)
  | fapply f lt=> qif f (map (term_assignment qic qif)  lt) 
 end.(*Definition 12*)
Definition compatible_QI qic qif := forall f lp t, forall s:variable -> value,
  let ru := rule_intro f lp t in (* f(p1, ..., pn) -> t *)
  (In ru prog) -> 
  term_assignment qic qif (subst s t) <= term_assignment qic qif (subst s (lhs_of_rule ru)).(* pour toute substitution, QI(t) <= QI(f(p1, ..., pn)) *)

Definition valid_QI qic qif cs :=
  (additive qic cs) /\ (mcs_is_max_constructor_size cs) /\ (constructor_non_zero cs) /\
  (subterm qif) /\ (monotonicity_qif qif) /\ (compatible_QI qic qif).Definition cache_bounded qic qif (c:cache): Prop  := 
  Forall (fun t => value_assignment qic (snd t) <= term_assignment qic qif (fst t)) c.

(* Specifications: *)
Lemma value_as_term_assignment qic qif: forall v:value, (term_assignment qic qif (term_from_value v)) = (value_assignment qic v).
Lemma qi_fapply_right_le_qi_fapply_left qic qif : forall proof_tree lp f c1, monotonicity_qif qif -> let l := map (proj_left (constructor:=constructor)) lp in let l' := map term_from_value (map (proj_right (constructor:=constructor)) lp) in let c := cache_left proof_tree in let v := proj_right proof_tree in (forall p, In p lp -> cache_bounded qic qif (cache_left p) -> value_assignment qic (proj_right p) <= term_assignment qic qif (proj_left p) /\ cache_bounded qic qif (cache_right p)) -> cache_bounded qic qif c1 -> cache_path c1 c lp = true -> andl (map wf lp) -> (term_assignment qic qif (fapply f l')) <= (term_assignment qic qif (fapply f l)).
Lemma qi_right_le_qi_fapply_left qic qif: forall proof_tree lp f c1, monotonicity_qif qif -> wf proof_tree -> let l := map (proj_left (constructor:=constructor)) lp in let l' := map term_from_value (map (proj_right (constructor:=constructor)) lp) in let c := cache_left proof_tree in let c' := cache_right proof_tree in let v := proj_right proof_tree in proj_left proof_tree = fapply f l' -> (forall p, In p lp -> cache_bounded qic qif (cache_left p) -> wf p -> value_assignment qic (proj_right p) <= term_assignment qic qif (proj_left p) /\ cache_bounded qic qif (cache_right p)) -> (cache_bounded qic qif c -> value_assignment qic v <= term_assignment qic qif (fapply f l')) -> cache_bounded qic qif c1 -> cache_bounded qic qif c' -> cache_path c1 c lp = true -> andl (map wf lp) -> value_assignment qic v <= term_assignment qic qif (fapply f l).
Lemma left_bound_to_right_bound qic qif cs:forall pi:cbv, valid_QI qic qif cs -> (wf pi) -> cache_bounded qic qif (cache_left pi) -> (value_assignment qic (proj_right pi) <= term_assignment qic qif (proj_left pi) /\ cache_bounded qic qif (cache_right pi)).
Lemma QI_never_increase_global qic qif cs: forall pi proof_tree:cbv, valid_QI qic qif cs -> wf proof_tree -> cache_bounded qic qif (cache_left proof_tree) -> InCBV pi proof_tree -> term_assignment qic qif (proj_left pi) <= term_assignment qic qif (proj_left proof_tree).
Lemma cache_left_bounded_global qic qif cs: forall pi proof_tree:cbv, valid_QI qic qif cs -> wf proof_tree -> cache_bounded qic qif (cache_left proof_tree) -> InCBV pi proof_tree -> cache_bounded qic qif (cache_left pi).