Skip to content
Snippets Groups Projects
Commit 8b49f226 authored by Ralf Jung's avatar Ralf Jung
Browse files

Merge branch 'ralf/f_equiv' into 'master'

f_equiv optimizations

See merge request iris/stdpp!325
parents 7d5f3593 cde5ccd9
No related branches found
No related tags found
No related merge requests found
......@@ -165,6 +165,11 @@ API-breaking change is listed.
- Enable `f_equiv` (and by extension `solve_proper`) to handle goals of the form
`f x ≡ g x` when `f ≡ g` is in scope, where `f` has a type like Iris's `-d>`
and `-n>`.
- Optimize `f_equiv` by doing more syntactic checking before handing off to
unification. This can make some uses 50x faster, but also makes the tactic
slightly weaker in case the left-hand side and right-hand side of the relation
call a function with arguments that are convertible but not syntactically
equal.
The following `sed` script should perform most of the renaming
(on macOS, replace `sed` by `gsed`, installed via e.g. `brew install gnu-sed`).
......
......@@ -374,46 +374,60 @@ Ltac f_equiv :=
destruct x
| H : ?R ?x ?y |- ?R2 (match ?x with _ => _ end) (match ?y with _ => _ end) =>
destruct H
(* First assume that the arguments need the same relation as the result *)
| |- ?R (?f _) _ => simple apply (_ : Proper (R ==> R) f)
| |- ?R (?f _ _) _ => simple apply (_ : Proper (R ==> R ==> R) f)
| |- ?R (?f _ _ _) _ => simple apply (_ : Proper (R ==> R ==> R ==> R) f)
| |- ?R (?f _ _ _ _) _ => simple apply (_ : Proper (R ==> R ==> R ==> R ==> R) f)
| |- ?R (?f _ _ _ _ _) _ => simple apply (_ : Proper (R ==> R ==> R ==> R ==> R ==> R) f)
(* First assume that the arguments need the same relation as the result. We
check the most restrictive pattern first: [(?f _) (?f _)] requires all but the
last argument to be syntactically equal. *)
| |- ?R (?f _) (?f _) => simple apply (_ : Proper (R ==> R) f)
| |- ?R (?f _ _) (?f _ _) => simple apply (_ : Proper (R ==> R ==> R) f)
| |- ?R (?f _ _ _) (?f _ _ _) => simple apply (_ : Proper (R ==> R ==> R ==> R) f)
| |- ?R (?f _ _ _ _) (?f _ _ _ _) => simple apply (_ : Proper (R ==> R ==> R ==> R ==> R) f)
| |- ?R (?f _ _ _ _ _) (?f _ _ _ _ _) => simple apply (_ : Proper (R ==> R ==> R ==> R ==> R ==> R) f)
(* For the case in which R is polymorphic, or an operational type class,
like equiv. *)
| |- (?R _) (?f _) _ => simple apply (_ : Proper (R _ ==> _) f)
| |- (?R _ _) (?f _) _ => simple apply (_ : Proper (R _ _ ==> _) f)
| |- (?R _ _ _) (?f _) _ => simple apply (_ : Proper (R _ _ _ ==> _) f)
| |- (?R _) (?f _ _) _ => simple apply (_ : Proper (R _ ==> R _ ==> _) f)
| |- (?R _ _) (?f _ _) _ => simple apply (_ : Proper (R _ _ ==> R _ _ ==> _) f)
| |- (?R _ _ _) (?f _ _) _ => simple apply (_ : Proper (R _ _ _ ==> R _ _ _ ==> _) f)
| |- (?R _) (?f _ _ _) _ => simple apply (_ : Proper (R _ ==> R _ ==> R _ ==> _) f)
| |- (?R _ _) (?f _ _ _) _ => simple apply (_ : Proper (R _ _ ==> R _ _ ==> R _ _ ==> _) f)
| |- (?R _ _ _) (?f _ _ _) _ => simple apply (_ : Proper (R _ _ _ ==> R _ _ _ R _ _ _ ==> _) f)
| |- (?R _) (?f _ _ _ _) _ => simple apply (_ : Proper (R _ ==> R _ ==> R _ ==> R _ ==> _) f)
| |- (?R _ _) (?f _ _ _ _) _ => simple apply (_ : Proper (R _ _ ==> R _ _ ==> R _ _ ==> R _ _ ==> _) f)
| |- (?R _ _ _) (?f _ _ _ _) _ => simple apply (_ : Proper (R _ _ _ ==> R _ _ _ ==> R _ _ _ ==> R _ _ _ ==> _) f)
| |- (?R _) (?f _ _ _ _ _) _ => simple apply (_ : Proper (R _ ==> R _ ==> R _ ==> R _ ==> R _ ==> _) f)
| |- (?R _ _) (?f _ _ _ _ _) _ => simple apply (_ : Proper (R _ _ ==> R _ _ ==> R _ _ ==> R _ _ ==> R _ _ ==> _) f)
| |- (?R _ _ _) (?f _ _ _ _ _) _ => simple apply (_ : Proper (R _ _ _ ==> R _ _ _ ==> R _ _ _ ==> R _ _ _ ==> R _ _ _ ==> _) f)
(* Next, try to infer the relation. Unfortunately, very often, it will turn
the goal into a Leibniz equality so we get stuck. *)
(* TODO: Can we exclude that instance? *)
| |- (?R _) (?f _) (?f _) => simple apply (_ : Proper (R _ ==> R _) f)
| |- (?R _ _) (?f _) (?f _) => simple apply (_ : Proper (R _ _ ==> R _ _) f)
| |- (?R _ _ _) (?f _) (?f _) => simple apply (_ : Proper (R _ _ _ ==> R _ _ _) f)
| |- (?R _) (?f _ _) (?f _ _) => simple apply (_ : Proper (R _ ==> R _ ==> R _) f)
| |- (?R _ _) (?f _ _) (?f _ _) => simple apply (_ : Proper (R _ _ ==> R _ _ ==> R _ _) f)
| |- (?R _ _ _) (?f _ _) (?f _ _) => simple apply (_ : Proper (R _ _ _ ==> R _ _ _ ==> R _ _ _) f)
| |- (?R _) (?f _ _ _) (?f _ _ _) => simple apply (_ : Proper (R _ ==> R _ ==> R _ ==> R _) f)
| |- (?R _ _) (?f _ _ _) (?f _ _ _) => simple apply (_ : Proper (R _ _ ==> R _ _ ==> R _ _ ==> R _ _) f)
| |- (?R _ _ _) (?f _ _ _) (?f _ _ _) => simple apply (_ : Proper (R _ _ _ ==> R _ _ _ ==> R _ _ _ ==> R _ _ _) f)
| |- (?R _) (?f _ _ _ _) (?f _ _ _ _) => simple apply (_ : Proper (R _ ==> R _ ==> R _ ==> R _ ==> R _) f)
| |- (?R _ _) (?f _ _ _ _) (?f _ _ _ _) => simple apply (_ : Proper (R _ _ ==> R _ _ ==> R _ _ ==> R _ _ ==> R _ _) f)
| |- (?R _ _ _) (?f _ _ _ _) (?f _ _ _ _) => simple apply (_ : Proper (R _ _ _ ==> R _ _ _ ==> R _ _ _ ==> R _ _ _ ==> R _ _ _) f)
| |- (?R _) (?f _ _ _ _ _) (?f _ _ _ _ _) => simple apply (_ : Proper (R _ ==> R _ ==> R _ ==> R _ ==> R _ ==> R _) f)
| |- (?R _ _) (?f _ _ _ _ _) (?f _ _ _ _ _) => simple apply (_ : Proper (R _ _ ==> R _ _ ==> R _ _ ==> R _ _ ==> R _ _ ==> R _ _) f)
| |- (?R _ _ _) (?f _ _ _ _ _) (?f _ _ _ _ _) => simple apply (_ : Proper (R _ _ _ ==> R _ _ _ ==> R _ _ _ ==> R _ _ _ ==> R _ _ _ ==> R _ _ _) f)
(* In case the function symbol differs, but the arguments are the same, maybe
we have a relation about those functions in our context that we can simply
apply. (The case where the arguments differ is a lot more complicated; with
the way we typically define the relations on function spaces it further
requires [Proper]ness of [f] or [g]). *)
| H : _ ?f ?g |- ?R (?f ?x) (?g ?x) => solve [simple apply H]
| H : _ ?f ?g |- ?R (?f ?x ?y) (?g ?x ?y) => solve [simple apply H]
(* Fallback case: try to infer the relation, and allow the function to not be
syntactically the same on both sides. Unfortunately, very often, it will
turn the goal into a Leibniz equality so we get stuck. Furthermore, looking
for instances in this order will mean that Coq will try to unify the
remaining arguments that we have not explicitly generalized, which can be
very slow -- but if we go for the opposite order, we will hit the Leibniz
equality fallback instance even more often. *)
(* TODO: Can we exclude that Leibniz equality instance? *)
| |- ?R (?f _) _ => simple apply (_ : Proper (_ ==> R) f)
| |- ?R (?f _ _) _ => simple apply (_ : Proper (_ ==> _ ==> R) f)
| |- ?R (?f _ _ _) _ => simple apply (_ : Proper (_ ==> _ ==> _ ==> R) f)
| |- ?R (?f _ _ _ _) _ => simple apply (_ : Proper (_ ==> _ ==> _ ==> _ ==> R) f)
| |- ?R (?f _ _ _ _ _) _ => simple apply (_ : Proper (_ ==> _ ==> _ ==> _ ==> _ ==> R) f)
(* In case the function symbol differs, but the arguments are the same,
maybe we have a relation about those functions in our context. *)
(* TODO: If only some of the arguments are the same, we could also
query for such relations. But that leads to a combinatorial
explosion about which arguments are and which are not the same. *)
| H : _ ?f ?g |- ?R (?f ?x) (?g ?x) => solve [simple apply H]
| H : _ ?f ?g |- ?R (?f ?x ?y) (?g ?x ?y) => solve [simple apply H]
end;
try simple apply reflexivity.
(* Only try reflexivity if the terms are syntactically equal. This avoids
very expensive failing unification. *)
try match goal with |- _ ?x ?x => simple apply reflexivity end.
Tactic Notation "f_equiv" "/=" := csimpl in *; f_equiv.
(** The tactic [solve_proper_unfold] unfolds the first head symbol, so that
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment