Ltac lifted_derives_L2R H :=
eapply ENTAIL_trans; [apply H |].
Ltac ENTAIL_L2R H :=
match type of H with
| @derives (environ -> mpred) _ (local (tc_environ _) && _) _ =>
eapply ENTAIL_trans; [apply H |]
| _ =>
eapply ENTAIL_trans; [apply derives_ENTAIL, H |]
end.
Ltac derives_bupd_L2R H :=
match type of H with
| @derives (environ -> mpred) _ (local (tc_environ _) && _) (|==> _) =>
eapply derives_bupd_trans; [apply H |]
| @derives (environ -> mpred) _ (local (tc_environ _) && _) _ =>
eapply derives_bupd_trans; [apply ENTAIL_derives_bupd, H |]
| _ =>
eapply derives_bupd_trans; [apply ENTAIL_derives_bupd, derives_ENTAIL, H |]
end.
Ltac derives_bupd0_L2R H :=
match type of H with
| @derives (environ -> mpred) _ (local (tc_environ _) && _) (|==> |> FF || _) =>
eapply derives_bupd0_trans; [apply H |]
| @derives (environ -> mpred) _ (local (tc_environ _) && _) (|==> _) =>
eapply derives_bupd0_trans; [apply derives_bupd_derives_bupd0, H |]
| @derives (environ -> mpred) _ (local (tc_environ _) && _) _ =>
eapply derives_bupd0_trans; [apply derives_bupd_derives_bupd0, ENTAIL_derives_bupd, H |]
| _ =>
eapply derives_bupd0_trans; [apply derives_bupd_derives_bupd0, ENTAIL_derives_bupd, derives_ENTAIL, H |]
end.
Ltac derives_full_L2R H :=
match type of H with
| @derives (environ -> mpred) _ (local (tc_environ ?Delta) && (allp_fun_id ?Delta && _)) (|==> |> FF || _) =>
eapply derives_full_trans; [apply H |]
| @derives (environ -> mpred) _ (local (tc_environ _) && _) (|==> |> FF || _) =>
eapply derives_full_trans; [apply derives_bupd0_derives_full, H |]
| @derives (environ -> mpred) _ (local (tc_environ _) && _) (|==> _) =>
eapply derives_full_trans; [apply derives_bupd0_derives_full, derives_bupd_derives_bupd0, H |]
| @derives (environ -> mpred) _ (local (tc_environ _) && _) _ =>
eapply derives_full_trans; [apply derives_bupd0_derives_full, derives_bupd_derives_bupd0, ENTAIL_derives_bupd, H |]
| _ =>
eapply derives_full_trans; [apply derives_bupd0_derives_full, derives_bupd_derives_bupd0, ENTAIL_derives_bupd, derives_ENTAIL, H |]
end.
Tactic Notation "derives_rewrite" "->" constr(H) :=
match goal with
| |- @derives (environ -> mpred) _ (local (tc_environ ?Delta) && (allp_fun_id ?Delta && _)) (|==> |> FF || _) =>
derives_full_L2R H
| |- @derives (environ -> mpred) _ (local (tc_environ _) && _) (|==> |> FF || _) =>
derives_bupd0_L2R H
| |- @derives (environ -> mpred) _ (local (tc_environ _) && _) (|==> _) =>
derives_bupd_L2R H
| |- @derives (environ -> mpred) _ (local (tc_environ _) && _) _ =>
ENTAIL_L2R H
| |- _ =>
lifted_derives_L2R H
end.
Ltac lifted_derives_R2L H :=
eapply derives_trans; [| apply H].
Ltac ENTAIL_R2L H :=
match type of H with
| @derives (environ -> mpred) _ (local (tc_environ _) && _) _ =>
eapply ENTAIL_trans; [| apply H]
| _ =>
eapply ENTAIL_trans; [| apply derives_ENTAIL, H]
end.
Ltac derives_bupd_R2L H :=
match type of H with
| @derives (environ -> mpred) _ (local (tc_environ _) && _) (|==> _) =>
eapply derives_bupd_trans; [| apply H]
| @derives (environ -> mpred) _ (local (tc_environ _) && _) _ =>
eapply derives_bupd_trans; [| apply ENTAIL_derives_bupd, H]
| _ =>
eapply derives_bupd_trans; [| apply ENTAIL_derives_bupd, derives_ENTAIL, H]
end.
Ltac derives_bupd0_R2L H :=
match type of H with
| @derives (environ -> mpred) _ (local (tc_environ _) && _) (|==> |> FF || _) =>
eapply derives_bupd0_trans; [| apply H]
| @derives (environ -> mpred) _ (local (tc_environ _) && _) (|==> _) =>
eapply derives_bupd0_trans; [| apply derives_bupd_derives_bupd0, H]
| @derives (environ -> mpred) _ (local (tc_environ _) && _) _ =>
eapply derives_bupd0_trans; [| apply derives_bupd_derives_bupd0, ENTAIL_derives_bupd, H]
| _ =>
eapply derives_bupd0_trans; [| apply derives_bupd_derives_bupd0, ENTAIL_derives_bupd, derives_ENTAIL, H]
end.
Ltac derives_full_R2L H :=
match type of H with
| @derives (environ -> mpred) _ (local (tc_environ ?Delta) && (allp_fun_id ?Delta && _)) (|==> |> FF || _) =>
eapply derives_bupd0_trans; [| apply H]
| @derives (environ -> mpred) _ (local (tc_environ _) && _) (|==> |> FF || _) =>
eapply derives_bupd0_trans; [| apply derives_bupd0_derives_full, H]
| @derives (environ -> mpred) _ (local (tc_environ _) && _) (|==> _) =>
eapply derives_bupd0_trans; [| apply derives_bupd0_derives_full, derives_bupd_derives_bupd0, H]
| @derives (environ -> mpred) _ (local (tc_environ _) && _) _ =>
eapply derives_bupd0_trans; [| apply derives_bupd0_derives_full, derives_bupd_derives_bupd0, ENTAIL_derives_bupd, H]
| _ =>
eapply derives_bupd0_trans; [| apply derives_bupd0_derives_full, derives_bupd_derives_bupd0, ENTAIL_derives_bupd, derives_ENTAIL, H]
end.
Tactic Notation "derives_rewrite" "<-" constr(H) :=
match goal with
| |- @derives (environ -> mpred) _ (local (tc_environ _) && _) (|==> |> FF || _) =>
derives_bupd0_R2L H
| |- @derives (environ -> mpred) _ (local (tc_environ _) && _) (|==> _) =>
derives_bupd_R2L H
| |- @derives (environ -> mpred) _ (local (tc_environ _) && _) _ =>
ENTAIL_R2L H
| |- _ =>
lifted_derives_R2L H
end.
Ltac solve_derives_trans :=
first [simple apply derives_full_refl | eapply derives_full_trans; [eassumption | solve_derives_trans]].

(* Specifications: *)
Lemma aux1_reduceR: forall P Q: environ -> mpred,
P |-- |==> Q ->
P |-- |==> |> FF || Q.
Lemma aux2_reduceR: forall P Q: environ -> mpred,
P |-- Q ->
P |-- |==> Q.