Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

autorewrite, rewrite, rewrite!, and rewrite? are all quadratic in the size of the goal even when there are no occurences #12600

Closed
JasonGross opened this issue Jun 27, 2020 · 4 comments · Fixed by #14253
Labels
kind: performance Improvements to performance and efficiency. part: rewriting tactics The rewrite, autorewrite, rewrite_strat, and setoid_rewrite tactics.
Milestone

Comments

@JasonGross
Copy link
Member

Description of the problem

Consider this code:

Axiom f : nat -> nat.
Axiom g : nat -> nat.
Axiom fg : forall x, f x = g x.

Axiom f' : nat -> nat -> nat.
Axiom g' : nat -> nat -> nat.
Axiom f'g' : forall x y, f' x y = g' x y.

Hint Rewrite fg : rew_fg.

Fixpoint comp_pow {A} (f : A -> A) (n : nat) (x : A) {struct n} : A
  := match n with
     | O => x
     | S n => f (comp_pow f n x)
     end.

Fixpoint comp_pow_tree {A} (f : A -> A -> A) (n : nat) (x : A) {struct n} : A
  := match n with
     | O => x
     | S n => f (comp_pow_tree f n x) (comp_pow_tree f n x)
     end.

Local Infix "^" := comp_pow : core_scope.

Notation goal_noop n := (forall x, (g^n) x = (g^n) x).
Notation goal_noop_exp lgn := (forall x, comp_pow_tree g' lgn x = comp_pow_tree g' lgn x).

Ltac redgoal _ := cbv [comp_pow comp_pow_tree]; intro.

On goals of the form goal_noop n, we can follow redgoal () with autorewrite with rew_fg, try rewrite !fg, try rewrite fg, or rewrite ?fg. All of these are quadratic in n:
rewrite-repeated-app-autorewrite-noop.svg
Interestingly, SSReflect's rewrite does not suffer from this issue, having performance linear in the size of the goal, and only takes more than a second on goals larger than 106 terms (goal_noop_exp lgn for lgn >= 19):
rewrite-repeated-app-ssrrewrite-noop
(the "cold" line is for a cold cache; the rest are run on the same goal immediately after running the cold-cache one)

This isn't super-high priority, but goals (e.g., in the category theory library) can easily reach upwards of 50,000 terms, and having autorewrite take 3 seconds (or more) to do nothing is kind-of slow.

What's causing the quadratic behavior here?

cc @ppedrot @mattam82

Coq Version

8.11

@JasonGross JasonGross added kind: performance Improvements to performance and efficiency. part: rewriting tactics The rewrite, autorewrite, rewrite_strat, and setoid_rewrite tactics. labels Jun 27, 2020
@JasonGross
Copy link
Member Author

@ppedrot Is this evar allocation or something else?

@ppedrot
Copy link
Member

ppedrot commented Jun 16, 2021

So, it's not so much evar allocation, but it's indeed indirectly due to the fact that the evar contexts are linear. The problem is that the old unification checks that a term is closed before deciding what to do (in Unification.matchrec), and rewrite relies on unification to apply the lemma. I had a patch somewhere that probably solved this problem which was even turned into a PR, but closed because no observable effect.

EDIT: this is #14253.

@ppedrot
Copy link
Member

ppedrot commented Jun 16, 2021

I confirm that #14253 solves the issue.

@JasonGross
Copy link
Member Author

@ppedrot #14253 only fixed this when the rewriting lemma has no evars, right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind: performance Improvements to performance and efficiency. part: rewriting tactics The rewrite, autorewrite, rewrite_strat, and setoid_rewrite tactics.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants