Section Ordering.
Set Implicit Arguments.
Variables variable function constructor : Type.
Notation value := (Syntax.value constructor).
Notation term := (Syntax.term variable function constructor).
Notation pattern := (Syntax.pattern variable constructor).
Notation rule := (Syntax.rule variable function constructor).
Notation cbv := (CBV_cache.cbv variable function constructor).
Notation cache := (CBV_cache.cache variable function constructor).
Variable variable_eq_dec : forall (x1 x2 : variable), {x1=x2}+{x1<>x2}.
Variable function_eq_dec : forall (x1 x2 : function), {x1=x2}+{x1<>x2}.
Variable constructor_eq_dec : forall (x1 x2 : constructor), {x1=x2}+{x1<>x2}.
Variable rule_default : rule.
Variable prog : list rule.
Variable max_arity : nat.
Notation wf :=
(CBV_cache.wf variable_eq_dec function_eq_dec constructor_eq_dec rule_default prog max_arity).
(* Function ranks and compatibility *)
Variable rank: function -> nat.
(* PPO *)
Inductive product {A: Type} (R : A -> A -> Prop) : list A -> list A -> Prop :=
| product_conseq : forall x y xs ys, x = y -> product R xs ys   -> product R (x::xs) (y::ys)
| product_consst : forall x y xs ys, R x y -> Forall2 (clos_refl R) xs ys -> product R (x::xs) (y::ys).
Inductive PPO: term -> term -> Prop :=
| ppo_constr_in    : forall s c lt,    In s lt            -> PPO s (capply c lt)
| ppo_fun_in       : forall s f lt,    In s lt            -> PPO s (fapply f lt)
| ppo_constr_sub   : forall s t c lt,  In t lt -> PPO s t -> PPO s (capply c lt)
| ppo_fun_sub      : forall s t f lt,  In t lt -> PPO s t -> PPO s (fapply f lt)
| ppo_constr_split : forall c ls f lt, (forall s, In s ls -> PPO s (fapply f lt))
-> PPO (capply c ls) (fapply f lt)
| ppo_funlt_split  : forall g ls f lt, rank g < rank f
-> (forall s, In s ls -> PPO s (fapply f lt))
-> PPO (fapply g ls) (fapply f lt)
| ppo_funeqv_split : forall g ls f lt, rank g = rank f
-> product PPO ls lt
-> PPO (fapply g ls) (fapply f lt).
Infix "≺ppo" := PPO (at level 80).
Infix "≼ppo" := (clos_refl PPO) (at level 80).
Hint Constructors product PPO.
Definition lt_wf_rect (n : nat) (P : nat -> Type)
(F : forall n, (forall m, m < n -> P m) -> P n) : P n :=
well_founded_induction_type (well_founded_ltof nat (fun m => m)) P F n.
Definition term_dec (t1 t2 : term) : {t1=t2}+{t1<>t2}.
Definition PPO_rule (r: rule) : Prop :=
match r with
| rule_intro f lp t => PPO t (fapply f (map (@term_from_pattern _ _ _) lp))
end.
Definition PPO_prog : Prop :=
forall r, In r prog -> PPO_rule r.
Definition activation_rank (p : cbv) : nat :=
match p with
| cbv_update _ _ _ _ (fapply f _) _ _ => rank f
| _                                   => 0
end.
End Ordering.

Lemma same_rank_same_prod vv ff cc lt ls rk rk':
(forall t s, In t lt -> In s ls ->
(forall f, In f (functions_of_term t) -> rk f = rk' f) ->
(forall f, In f (functions_of_term s) -> rk f = rk' f) ->
PPO rk t s -> PPO rk' t s) ->
(forall f, In f (flat_map (@functions_of_term vv ff cc) lt) -> rk f = rk' f) ->
(forall f, In f (flat_map (@functions_of_term _ _ _) ls) -> rk f = rk' f) ->
product (PPO rk) lt ls -> product (PPO rk') lt ls.