Require Export RelDefinitions.
(** ** Union of relations *)
Definition rel_union {A B} (R1 R2: rel A B): rel A B :=
fun x y => R1 x y \/ R2 x y.
Arguments rel_union {_ _} R1%rel R2%rel _ _.
Infix "\/" := rel_union : rel_scope.
Global Instance rel_union_subrel {A B}:
Monotonic (@rel_union A B) (subrel ++> subrel ++> subrel).
Global Instance rel_union_subrel_params:
Params (@rel_union) 4.
Defined.
(** Since we're forced to commit to a branch, we can't use [RIntro], but can still provide [RExists] instances. *)
Hint Extern 0 (RExists _ (_ \/ _) _ _) =>
eapply rel_union_rexists_l : typeclass_instances.
Hint Extern 0 (RExists _ (_ \/ _) _ _) =>
eapply rel_union_rexists_r : typeclass_instances.
(** More often, we can solve a [rel_union] goal using a monotonicity property, and the [subrel] instances below. *)
Hint Extern 0 (RExists _ subrel _ (_ \/ _)%rel) =>
eapply rel_union_subrel_rexists_l : typeclass_instances.
Hint Extern 0 (RExists _ subrel _ (_ \/ _)%rel) =>
eapply rel_union_subrel_rexists_r : typeclass_instances.
Hint Extern 2 (RIntro _ subrel (_ \/ _)%rel _) =>
eapply rel_union_lub : typeclass_instances.
Hint Extern 1 (Reflexive (_ \/ _)) =>
eapply rel_union_refl_l : typeclass_instances.
Hint Extern 1 (Reflexive (_ \/ _)) =>
eapply rel_union_refl_r : typeclass_instances.
Hint Extern 1 (Coreflexive (_ \/ _)) =>
eapply rel_union_corefl : typeclass_instances.
Hint Extern 1 (Symmetric (_ \/ _)) =>
eapply rel_union_sym : typeclass_instances.
(** ** Intersection of relations *)
Definition rel_inter {A B} (R1 R2: rel A B): rel A B :=
fun x y => R1 x y /\ R2 x y.
Arguments rel_inter {_ _} R1%rel R2%rel _ _.
Infix "/\" := rel_inter : rel_scope.
Global Instance rel_inter_subrel {A B}:
Monotonic (@rel_inter A B) (subrel ++> subrel ++> subrel).
Global Instance rel_inter_params:
Params (@rel_inter) 4.
Defined.
(** In some cases, the relation in the goal will cause existential variables to be instantiated accordingly; for instance, [rstep] run on [?R x y |- (R1 /\ R2) x y] will instantiate [?R := R1 /\ R2]. Because of this, splitting a [rel_inter] goal into two subgoals may cause a dead-end and we have to use [RExists] for the following rule. *)
Hint Extern 0 (RExists _ (_ /\ _) _ _) =>
eapply rel_inter_rexists : typeclass_instances.
Hint Extern 0 (RExists _ subrel (_ /\ _)%rel _) =>
eapply rel_inter_subrel_rexists_l : typeclass_instances.
Hint Extern 0 (RExists _ subrel (_ /\ _)%rel _) =>
eapply rel_inter_subrel_rexists_r : typeclass_instances.
Hint Extern 2 (RIntro _ subrel _ (_ /\ _)%rel) =>
eapply rel_inter_glb : typeclass_instances.
Hint Extern 2 (Reflexive (_ /\ _)) =>
eapply rel_inter_refl : typeclass_instances.
Hint Extern 1 (Coreflexive (_ /\ _)) =>
eapply rel_inter_corefl_l : typeclass_instances.
Hint Extern 1 (Coreflexive (_ /\ _)) =>
eapply rel_inter_corefl_r : typeclass_instances.
Hint Extern 2 (Transitive (_ /\ _)) =>
eapply rel_inter_trans : typeclass_instances.
Hint Extern 2 (Symmetric (_ /\ _)) =>
eapply rel_inter_sym : typeclass_instances.
Global Instance rel_inter_flip_sym {A} (R: rel A A):
Symmetric (R /\ flip R).
(** On a related note, a symmetric subrelation of [R] is also a subrelation of its inverse. *)
Hint Extern 60 (RStep _ (subrel _ (flip _))) =>
eapply subrel_sym_flip : typeclass_instances.
(** ** Implication *)
Definition rel_impl {A B} (R1 R2: rel A B): rel A B :=
fun x y => R1 x y -> R2 x y.
Global Instance rel_impl_subrel {A B}:
Monotonic (@rel_impl A B) (subrel --> subrel ++> subrel).
Global Instance rel_impl_subrel_params:
Params (@rel_impl) 4.
Defined.
Hint Extern 0 (RIntro _ (rel_impl _ _) _ _) =>
eapply rel_impl_rintro : typeclass_instances.
Hint Extern 0 (RElim (rel_impl _ _) _ _ _ _) =>
eapply rel_impl_relim : typeclass_instances.

Lemma rel_impl_subrel_codomain {A B} (R1 R2: rel A B):
Related R2 (rel_impl R1 R2) subrel.