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.

Lemma product_trans (A: Type) (R : A -> A -> Prop) lt1 lt2 lt3 :
(forall t1 t2 t3, In t1 lt1 -> In t2 lt2 -> In t3 lt3 -> R t1 t2 -> R t2 t3 -> R t1 t3) ->
product R lt1 lt2 -> product R lt2 lt3 -> product R lt1 lt3.