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 !325
parents 7d5f3593 cde5ccd9
No related branches found
No related tags found
1 merge request!325f_equiv optimizations
Pipeline #54521 passed
...@@ -165,6 +165,11 @@ API-breaking change is listed. ...@@ -165,6 +165,11 @@ API-breaking change is listed.
- Enable `f_equiv` (and by extension `solve_proper`) to handle goals of the form - 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>` `f x ≡ g x` when `f ≡ g` is in scope, where `f` has a type like Iris's `-d>`
and `-n>`. 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 The following `sed` script should perform most of the renaming
(on macOS, replace `sed` by `gsed`, installed via e.g. `brew install gnu-sed`). (on macOS, replace `sed` by `gsed`, installed via e.g. `brew install gnu-sed`).
......
...@@ -374,46 +374,60 @@ Ltac f_equiv := ...@@ -374,46 +374,60 @@ Ltac f_equiv :=
destruct x destruct x
| H : ?R ?x ?y |- ?R2 (match ?x with _ => _ end) (match ?y with _ => _ end) => | H : ?R ?x ?y |- ?R2 (match ?x with _ => _ end) (match ?y with _ => _ end) =>
destruct H destruct H
(* First assume that the arguments need the same relation as the result *) (* First assume that the arguments need the same relation as the result. We
| |- ?R (?f _) _ => simple apply (_ : Proper (R ==> R) f) check the most restrictive pattern first: [(?f _) (?f _)] requires all but the
| |- ?R (?f _ _) _ => simple apply (_ : Proper (R ==> R ==> R) f) last argument to be syntactically equal. *)
| |- ?R (?f _ _ _) _ => simple apply (_ : Proper (R ==> R ==> R ==> R) f) | |- ?R (?f _) (?f _) => simple apply (_ : Proper (R ==> R) f)
| |- ?R (?f _ _ _ _) _ => simple apply (_ : Proper (R ==> R ==> R ==> R ==> R) f) | |- ?R (?f _ _) (?f _ _) => simple apply (_ : Proper (R ==> R ==> R) f)
| |- ?R (?f _ _ _ _ _) _ => simple apply (_ : Proper (R ==> R ==> 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 ==> R) f)
(* For the case in which R is polymorphic, or an operational type class, (* For the case in which R is polymorphic, or an operational type class,
like equiv. *) like equiv. *)
| |- (?R _) (?f _) _ => simple apply (_ : Proper (R _ ==> _) f) | |- (?R _) (?f _) (?f _) => simple apply (_ : Proper (R _ ==> R _) f)
| |- (?R _ _) (?f _) _ => simple apply (_ : Proper (R _ _ ==> _) f) | |- (?R _ _) (?f _) (?f _) => simple apply (_ : Proper (R _ _ ==> R _ _) f)
| |- (?R _ _ _) (?f _) _ => simple apply (_ : Proper (R _ _ _ ==> _) f) | |- (?R _ _ _) (?f _) (?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 _ _) (?f _ _) => simple apply (_ : Proper (R _ ==> R _ ==> R _) f)
| |- (?R _ _ _) (?f _ _) _ => simple apply (_ : Proper (R _ _ _ ==> R _ _ _ ==> _) f) | |- (?R _ _) (?f _ _) (?f _ _) => simple apply (_ : Proper (R _ _ ==> R _ _ ==> R _ _) f)
| |- (?R _) (?f _ _ _) _ => simple apply (_ : Proper (R _ ==> R _ ==> R _ ==> _) f) | |- (?R _ _ _) (?f _ _) (?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 _ _ _) (?f _ _ _) => simple apply (_ : Proper (R _ ==> R _ ==> R _ ==> R _) f)
| |- (?R _) (?f _ _ _ _) _ => simple apply (_ : Proper (R _ ==> R _ ==> R _ ==> R _ ==> _) f) | |- (?R _ _) (?f _ _ _) (?f _ _ _) => simple apply (_ : Proper (R _ _ ==> R _ _ ==> R _ _ ==> R _ _) f)
| |- (?R _ _) (?f _ _ _ _) _ => simple apply (_ : Proper (R _ _ ==> R _ _ ==> R _ _ ==> R _ _ ==> _) f) | |- (?R _ _ _) (?f _ _ _) (?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 _ _ _ _) (?f _ _ _ _) => simple apply (_ : Proper (R _ ==> R _ ==> R _ ==> R _ ==> R _) f)
| |- (?R _ _) (?f _ _ _ _ _) _ => simple apply (_ : Proper (R _ _ ==> R _ _ ==> R _ _ ==> R _ _ ==> R _ _ ==> _) f) | |- (?R _ _) (?f _ _ _ _) (?f _ _ _ _) => simple apply (_ : Proper (R _ _ ==> R _ _ ==> R _ _ ==> R _ _ ==> R _ _) f)
| |- (?R _ _ _) (?f _ _ _ _ _) _ => simple apply (_ : Proper (R _ _ _ ==> R _ _ _ ==> R _ _ _ ==> R _ _ _ ==> R _ _ _ ==> _) f) | |- (?R _ _ _) (?f _ _ _ _) (?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. *) | |- (?R _) (?f _ _ _ _ _) (?f _ _ _ _ _) => simple apply (_ : Proper (R _ ==> R _ ==> R _ ==> R _ ==> R _ ==> R _) f)
(* TODO: Can we exclude that instance? *) | |- (?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) | |- ?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; 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. Tactic Notation "f_equiv" "/=" := csimpl in *; f_equiv.
(** The tactic [solve_proper_unfold] unfolds the first head symbol, so that (** 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