Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit 72d3b6e

Browse files
kim-emrobertylewisScott Morrisonbryangingechengebner
authored
feat(tactic/equiv_rw): incorporating equiv_functor (#2301)
* feat(tactic): rewriting along equivalences * header * minor * type * actually, rewriting the goal under functors is easy * rewriting inside function types * more * way better * improving comments * fun * feat(data/equiv): pi_congr * various * feat(data/equiv): sigma_congr * docstrings * change case for consistency * tidying up * minor * minor * switching names * fixes * add some tracing routines for convenience * feat(tactic/core): trace_for * typo * oops * oops * various * chore(tactic/solve_by_elim): cleanup * cleanup * what happened to my commit? * fix * fix * rename to trace_if_enabled * fixed? * Tweak comments * feat(tactic/solve_by_elim): add accept parameter to prune tree search * when called with empty lemmas, use the same default set as the interactive tactic * trace_state_if_enabled * Update src/data/equiv/basic.lean * implicit arguments * stop cheating with [] ~ none * indenting * yay, working via solve_by_elim * pretty good * various * various * docstring * fix docstrings * more docs * docs * feat(data/equiv/functor): bifunctor.map_equiv * bifunctors * test rewriting under unique * start * sketch of equiv_functor * rewriting in subtypes * add documentation, and make the function an explicit argument * documentation * fix doc-strings * typos * minor * adding demonstration of transporting semigroup * update * removing unimpressive inhabited example; easier later * Update .vscode/settings.json * err * trying to transport through monoid * err? * much better * improve documentation of accept, and add doc-string * fix duplicated namespace * improve docs * feat(logic/basic): trivial transport lemmas * try again with documentation * update * oops * oops * omit * revert unnecessary change * fix doc-string * chore(data/equiv/basic): simp to_fun to coe * feat(tactic/equiv_rw): incorporating equiv_functor * rename adapt_equiv * simplify the equivalence produced, and provide a tactic to access the equivalence * add max_steps option * add decl_name to add_tactic_doc * fix add_tactic_doc * satisfying linter * fix names * finish fix * add defaults for cfg arguments * remove simplify_term, which already existed as expr.simp * remove duplicate functions that have been PRd separately * no need for accept * Update src/tactic/equiv_rw.lean Co-Authored-By: Bryan Gin-ge Chen <bryangingechen@gmail.com> * Update src/tactic/equiv_rw.lean Co-Authored-By: Gabriel Ebner <gebner@gebner.org> * replace max_steps with max_depth * use solve_aux * add missing simp lemmas about arrow_congr' * fix failing test, by making sure we don't leave any ≃ goals on the table * add comment * comment out trace output * fix fields Co-authored-by: Rob Lewis <Rob.y.lewis@gmail.com> Co-authored-by: Scott Morrison <scott.morrison@anu.edu.au> Co-authored-by: Bryan Gin-ge Chen <bryangingechen@gmail.com> Co-authored-by: Gabriel Ebner <gebner@gebner.org> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent b508d0e commit 72d3b6e

File tree

4 files changed

+63
-53
lines changed

4 files changed

+63
-53
lines changed

src/category/equiv_functor.lean

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,4 @@ instance of_is_lawful_functor
6464
map_refl' := λ α, by { ext, apply is_lawful_functor.id_map, },
6565
map_trans' := λ α β γ k h, by { ext x, apply (is_lawful_functor.comp_map k h x), } }
6666

67-
-- TODO Include more examples here;
68-
-- once `equiv_rw` is available these are hopefully easy to construct,
69-
-- and in turn make `equiv_rw` more powerful.
70-
instance equiv_functor_unique : equiv_functor unique :=
71-
{ map := λ α β e, equiv.unique_congr e, }
72-
7367
end equiv_functor
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/-
2+
Copyright (c) 2020 Scott Morrison. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Author: Scott Morrison
5+
-/
6+
import category.equiv_functor
7+
import tactic.equiv_rw
8+
9+
/-!
10+
# `equiv_functor` instances
11+
12+
We derive some `equiv_functor` instances, to enable `equiv_rw` to rewrite under these functions.
13+
-/
14+
15+
open equiv
16+
17+
instance equiv_functor_unique : equiv_functor unique :=
18+
{ map := λ α β e, equiv.unique_congr e, }
19+
20+
instance equiv_functor_perm : equiv_functor perm :=
21+
{ map := λ α β e p, (e.symm.trans p).trans e }

src/tactic/equiv_rw.lean

Lines changed: 14 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Copyright (c) 2019 Scott Morrison. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Scott Morrison
55
-/
6-
import data.equiv.functor
6+
import category.equiv_functor
77

88
/-!
99
# The `equiv_rw` tactic transports goals or hypotheses along equivalences.
@@ -26,8 +26,7 @@ As an example, with `t = option α`, it will generate `functor.map_equiv option
2626
This is achieved by generating a new synthetic goal `%%t ≃ _`,
2727
and calling `solve_by_elim` with an appropriate set of congruence lemmas.
2828
To avoid having to specify the relevant congruence lemmas by hand,
29-
we mostly rely on `functor.map_equiv` and `bifunctor.map_equiv`
30-
(and, in a future PR, `equiv_functor.map_equiv`, see below),
29+
we mostly rely on `equiv_functor.map_equiv` and `bifunctor.map_equiv`
3130
along with some structural congruence lemmas such as
3231
* `equiv.arrow_congr'`,
3332
* `equiv.subtype_equiv_of_subtype'`,
@@ -42,21 +41,9 @@ revert this, and then attempt to `generalize`, replacing all occurrences of `e x
4241
before `intro`ing and `subst`ing `h`, and renaming `y` back to `x`.
4342
4443
## Future improvements
45-
While `equiv_rw` will rewrite under type-level functors (e.g. `option` and `list`),
46-
many constructions are only functorial with respect to equivalences
47-
(essentially, because of both positive and negative occurrences of the type being rewritten).
48-
At the moment, we only handle constructions of this form (e.g. `unique` or `ring`) by
49-
including explicit `equiv.*_congr` lemmas in the list provided to `solve_by_elim`.
50-
51-
A (near) future PR will introduce `equiv_functor`,
52-
a typeclass for functions which are functorial with respect to equivalences,
53-
and use these instances rather than hard-coding the `congr` lemmas here.
54-
55-
`equiv_functor` is not included in the initial implementation of `equiv_rw`, simply because
56-
the best way to construct an instance of `equiv_functor has_add` is to use `equiv_rw`!
57-
In fact, in a slightly more distant future PR I anticipate that
58-
`derive equiv_functor` should work on many examples, and
59-
we can incrementally bootstrap the strength of `equiv_rw`.
44+
In a future PR I anticipate that `derive equiv_functor` should work on many examples,
45+
(internally using `transport`, which is in turn based on `equiv_rw`)
46+
and we can incrementally bootstrap the strength of `equiv_rw`.
6047
6148
An ambitious project might be to add `equiv_rw!`,
6249
a tactic which, when failing to find appropriate `equiv_functor` instances,
@@ -73,15 +60,10 @@ but this will wait for another subsequent PR.
7360

7461
namespace tactic
7562

76-
/-- A hard-coded list of names of lemmas used for constructing congruence equivalences. -/
63+
/-- A list of lemmas used for constructing congruence equivalences. -/
7764

78-
-- TODO: This should not be a hard-coded list.
79-
-- We could accommodate the remaining "non-structural" lemmas using
80-
-- `equiv_functor` instances.
81-
-- Moreover, these instances can typically be `derive`d.
82-
83-
-- (Scott): I have not incorporated `equiv_functor` as part of this PR,
84-
-- as the best way to construct instances, either by hand or using `derive`, is to use this tactic!
65+
-- Although this looks 'hard-coded', in fact the lemma `equiv_functor.map_equiv`
66+
-- allows us to extend `equiv_rw` simply by constructing new instance so `equiv_functor`.
8567

8668
-- TODO: We should also use `category_theory.functorial` and `category_theory.hygienic` instances.
8769
-- (example goal: we could rewrite along an isomorphism of rings (either as `R ≅ S` or `R ≃+* S`)
@@ -91,10 +73,8 @@ meta def equiv_congr_lemmas : tactic (list expr) :=
9173
do exprs ←
9274
[
9375
`equiv.of_iff,
94-
-- These are functorial w.r.t equiv,
95-
-- and so will be subsumed by `equiv_functor.map_equiv` in a subsequent PR.
96-
-- Many more could be added, but will wait for that framework.
97-
`equiv.perm_congr, `equiv.equiv_congr, `equiv.unique_congr,
76+
-- TODO decide what to do with this; it's an equiv_bifunctor?
77+
`equiv.equiv_congr,
9878
-- The function arrow is technically a bifunctor `Typeᵒᵖ → Type → Type`,
9979
-- but the pattern matcher will never see this.
10080
`equiv.arrow_congr',
@@ -112,8 +92,8 @@ do exprs ←
11292
`equiv.Pi_congr_left',
11393
-- Handles `sum` and `prod`, and many others:
11494
`bifunctor.map_equiv,
115-
-- Handles `list`, `option`, and many others:
116-
`functor.map_equiv,
95+
-- Handles `list`, `option`, `unique`, and many others:
96+
`equiv_functor.map_equiv,
11797
-- We have to filter results to ensure we don't cheat and use exclusively `equiv.refl` and `iff.refl`!
11898
`equiv.refl,
11999
`iff.refl
@@ -254,9 +234,9 @@ with all occurrences of `h` in other hypotheses and the goal replaced with `e.sy
254234
`equiv_rw e` will attempt to transport the goal along an equivalence `e : α ≃ β`.
255235
In its minimal form it replaces the goal `⊢ α` with `⊢ β` by calling `apply e.inv_fun`.
256236
257-
`equiv_rw` will also try rewriting under functors, so can turn
237+
`equiv_rw` will also try rewriting under (equiv_)functors, so can turn
258238
a hypothesis `h : list α` into `h : list β` or
259-
a goal `⊢ option α` into `⊢ option β`.
239+
a goal `⊢ unique α` into `⊢ unique β`.
260240
261241
The maximum search depth for rewriting in subexpressions is controlled by
262242
`equiv_rw e {max_depth := n}`.

test/equiv_rw.lean

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Scott Morrison
55
-/
66
import tactic.equiv_rw
7+
import category.equiv_functor.instances -- these make equiv_rw more powerful!
78

89
-- Uncomment this line to observe the steps of constructing appropriate equivalences.
910
-- set_option trace.equiv_rw_type true
@@ -43,12 +44,20 @@ begin
4344
exact a,
4445
end
4546

47+
-- Verify that `equiv_rw` will rewrite under `equiv_functor` instances.
4648
example {α β : Type} (u : unique α) (e : α ≃ β) : β :=
4749
begin
4850
equiv_rw e at u,
4951
apply inhabited.default,
5052
end
5153

54+
example {α β : Type} (p : equiv.perm α) (e : α ≃ β) : equiv.perm β :=
55+
begin
56+
equiv_rw e at p,
57+
exact p,
58+
end
59+
60+
5261
-- We can rewrite the goal under functors.
5362
example {α β : Type} (e : α ≃ β) (b : β) : option α :=
5463
begin
@@ -203,11 +212,12 @@ begin
203212
end
204213

205214
-- Demonstrate using `equiv_rw` to build new instances of `equiv_functor`
206-
-- (which isn't yet in this PR, so we only define the fields without assembling them)
207215
-- Observe that the next three declarations could easily be implemented by a tactic.
208216

209217
attribute [ext] semigroup
210218

219+
-- This has been automated in the `transport` branch,
220+
-- so we won't attempt to write a deriver handler until we join with that.
211221
def semigroup.map {α β : Type} (e : α ≃ β) : semigroup α → semigroup β :=
212222
begin
213223
intro S, fconstructor,
@@ -217,20 +227,25 @@ begin
217227
{ intros, dsimp, simp, apply S.mul_assoc, }
218228
end
219229

220-
-- Note this is purely formal, and will be provided by `equiv_functor` automatically.
221-
@[simps]
222-
def semigroup.map_equiv {α β : Type} (e : α ≃ β) : semigroup α ≃ semigroup β :=
223-
{ to_fun := semigroup.map e,
224-
inv_fun := semigroup.map e.symm,
225-
left_inv := by { intro x, funext, ext, dsimp [semigroup.map], simp, },
226-
right_inv := by { intro x, funext, ext, dsimp [semigroup.map], simp, }, }
227-
228-
lemma semigroup.map_id (α : Type) : semigroup.map_equiv (equiv.refl α) = equiv.refl (semigroup α) :=
230+
lemma semigroup.id_map (α : Type) : semigroup.map (equiv.refl α) = id :=
229231
by { ext, refl, }
230232

231-
lemma semigroup.map_comp {α β γ : Type} (e : α ≃ β) (f : β ≃ γ) :
232-
(semigroup.map_equiv e).trans (semigroup.map_equiv f) = semigroup.map_equiv (e.trans f) :=
233-
by { ext, dsimp [semigroup.map, semigroup.map_equiv], simp, }
233+
lemma semigroup.map_map {α β γ : Type} (e : α ≃ β) (f : β ≃ γ) :
234+
semigroup.map (e.trans f) = (semigroup.map f) ∘ (semigroup.map e) :=
235+
by { ext, dsimp [semigroup.map], simp, }
236+
237+
-- TODO (after joining the `transport` branch) create a derive handler for this
238+
instance : equiv_functor semigroup :=
239+
{ map := λ α β e, semigroup.map e,
240+
map_refl' := semigroup.id_map,
241+
map_trans' := λ α β γ e f, semigroup.map_map e f, }
242+
243+
-- Verify that we can now use `equiv_rw` under `semigroup`:
244+
example {α : Type} [I : semigroup α] {β : Type} (e : α ≃ β) : semigroup β :=
245+
begin
246+
equiv_rw e at I,
247+
exact I,
248+
end
234249

235250
-- Now we do `monoid`, to try out a structure with constants.
236251
attribute [ext] monoid

0 commit comments

Comments
 (0)