Hint Extern 1 (RElim (_ ++> _) _ _ _ _) =>
eapply arrow_relim : typeclass_instances.
(** *** Dependent products *)
(** Now we consider the dependent case. The definition of [forall_rel] is somewhat involved, but you can think of relating [f] and [g] in the context of a structure-preserving transformation from a quiver ([V], [E]) to the quiver ([Type], [rel]). Like a functor, it has two components: [FV] maps nodes to types, and [FE] maps edges to relations. Then, [forall_rel FE f g] states that given an edge [(e : E v1 v2)], the images [f v1] and [g v2] are related by the corresponding relation [FE v1 v2 e]. We will write [forall_rel FE f g] as [(forallr e @ v1 v2 : E, FE[v1,v2,e]) f g]. Notice that this notation binds [v1] and [v2] as well as [e].  If that makes no sense, you can think of specific source quivers. So for instance, oftentimes we will want to use ([Type], [rel]) as the source quiver too. This corresponds to parametric polymorphism. The type of [Some] is [forall A : Type, A -> option A]; the corresponding logical relation is [forallr R @ A1 A2 : rel, R ++> option_rel R]. Stating that [Monotonic Some (foralr R @ A1 A2 : rel, R ++> option_rel R)] means that, given any relation [R] and elements [x1] and [x2], if [R] relates [x1] and [x2], then [option_rel R] will relate [Some x1] and [Some x2].  Another example from [liblayers] is the quiver of our data-indexed simulation relations [simrel : layerdata -> layerdata -> Type]. Here the structure-preserving transformations are our simulation relation diagrams, which have types such as [lsim : forall D1 D2, simrel D1 D2 -> rel (layer D1) (layer D2)] or [psim : forall {D1 D2}, simrel D1 D2 -> rel (primsem D1) (primsem D2)]. Then, the monotonicity of a data-indexed function — say, [foo: forall D : layerdata, layer D -> primsem D] — can be expressed as [Monotonic foo (forall R @ D1 D2 : simrel, siml D1 D2 R ++> simp D1 D2 R) foo].  This definition is the same as [respectful_hetero]. *)
Definition forall_rel {V1 V2} {E: V1->V2->Type} {FV1: V1->Type} {FV2: V2->Type}:
(forall v1 v2, E v1 v2 -> rel (FV1 v1) (FV2 v2)) ->
rel (forall v1, FV1 v1) (forall v2, FV2 v2) :=
fun FE f g =>
forall v1 v2 (e: E v1 v2), FE v1 v2 e (f v1) (g v2).
Arguments forall_rel {V1%type V2%type E%type FV1%type FV2%type} FE%rel _ _.
Notation "'forallr' e @ v1 v2 : E , R" :=
(forall_rel (E := E) (fun v1 v2 e => R))
(at level 200, e ident, v1 ident, v2 ident, right associativity) : rel_scope.
Notation "'forallr' e @ v1 v2 , R" :=
(forall_rel (fun v1 v2 e => R))
(at level 200, e ident, v1 ident, v2 ident, right associativity) : rel_scope.
Notation "'forallr' e : E , R" :=
(forall_rel (E := E) (fun _ _ e => R))
(at level 200, e ident, right associativity) : rel_scope.
Notation "'forallr' e , R" :=
(forall_rel (fun _ _ e => R))
(at level 200, e ident, right associativity) : rel_scope.

Lemma forall_rintro {V1 V2 E F1 F2} (FE: forall x y, _ -> rel _ _) f g:
RIntro
(forall u v e, FE u v e (f u) (g v))
(@forall_rel V1 V2 E F1 F2 FE) f g.