Skip to content

Commit d0b0a73

Browse files
committed
feat: port Algebra/CovariantAndContravariant (#467)
These are mostly instances required so that lemmas needed for linarith actually fire in the presence of `LinearOrderedCommRing`. - [x] depends on #457 Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
1 parent 12db1d9 commit d0b0a73

File tree

4 files changed

+410
-0
lines changed

4 files changed

+410
-0
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Mathlib.Algebra.CovariantAndContravariant
12
import Mathlib.Algebra.Group.Basic
23
import Mathlib.Algebra.Group.Commute
34
import Mathlib.Algebra.Group.Defs
Lines changed: 389 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,389 @@
1+
/-
2+
Copyright (c) 2021 Damiano Testa. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Damiano Testa
5+
-/
6+
import Mathlib.Algebra.Group.Defs
7+
import Mathlib.Order.Basic
8+
import Mathlib.Order.Monotone
9+
10+
/-!
11+
12+
# Covariants and contravariants
13+
14+
This file contains general lemmas and instances to work with the interactions between a relation and
15+
an action on a Type.
16+
17+
The intended application is the splitting of the ordering from the algebraic assumptions on the
18+
operations in the `ordered_[...]` hierarchy.
19+
20+
The strategy is to introduce two more flexible typeclasses, `CovariantClass` and
21+
`ContravariantClass`:
22+
23+
* `CovariantClass` models the implication `a ≤ b → c * a ≤ c * b` (multiplication is monotone),
24+
* `ContravariantClass` models the implication `a * b < a * c → b < c`.
25+
26+
Since `co(ntra)variant_class` takes as input the operation (typically `(+)` or `(*)`) and the order
27+
relation (typically `(≤)` or `(<)`), these are the only two typeclasses that I have used.
28+
29+
The general approach is to formulate the lemma that you are interested in and prove it, with the
30+
`ordered_[...]` typeclass of your liking. After that, you convert the single typeclass,
31+
say `[ordered_cancel_monoid M]`, into three typeclasses, e.g.
32+
`[left_cancel_semigroup M] [partial_order M] [CovariantClass M M (function.swap (*)) (≤)]`
33+
and have a go at seeing if the proof still works!
34+
35+
Note that it is possible to combine several co(ntra)variant_class assumptions together.
36+
Indeed, the usual ordered typeclasses arise from assuming the pair
37+
`[CovariantClass M M (*) (≤)] [ContravariantClass M M (*) (<)]`
38+
on top of order/algebraic assumptions.
39+
40+
A formal remark is that normally `CovariantClass` uses the `(≤)`-relation, while
41+
`ContravariantClass` uses the `(<)`-relation. This need not be the case in general, but seems to be
42+
the most common usage. In the opposite direction, the implication
43+
```lean
44+
[semigroup α] [partial_order α] [ContravariantClass α α (*) (≤)] => left_cancel_semigroup α
45+
```
46+
holds -- note the `co*ntra*` assumption on the `(≤)`-relation.
47+
48+
# Formalization notes
49+
50+
We stick to the convention of using `function.swap (*)` (or `function.swap (+)`), for the
51+
typeclass assumptions, since `function.swap` is slightly better behaved than `flip`.
52+
However, sometimes as a **non-typeclass** assumption, we prefer `flip (*)` (or `flip (+)`),
53+
as it is easier to use.
54+
55+
56+
# Porting notes
57+
58+
In mathlib3 we used the `is_trans` typeclass from Lean 3 core,
59+
and we have switched to the `Trans` typeclass from Lean 4 core.
60+
61+
-/
62+
63+
64+
-- TODO: convert `has_exists_mul_of_le`, `has_exists_add_of_le`?
65+
-- TODO: relationship with `con/add_con`
66+
-- TODO: include equivalence of `left_cancel_semigroup` with
67+
-- `semigroup partial_order ContravariantClass α α (*) (≤)`?
68+
-- TODO : use ⇒, as per Eric's suggestion? See
69+
-- https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/ordered.20stuff/near/236148738
70+
-- for a discussion.
71+
open Function
72+
73+
section Variants
74+
75+
variable {M N : Type _} (μ : M → N → N) (r : N → N → Prop)
76+
77+
variable (M N)
78+
79+
/-- `Covariant` is useful to formulate succintly statements about the interactions between an
80+
action of a Type on another one and a relation on the acted-upon Type.
81+
82+
See the `CovariantClass` doc-string for its meaning. -/
83+
def Covariant : Prop :=
84+
∀ (m) {n₁ n₂}, r n₁ n₂ → r (μ m n₁) (μ m n₂)
85+
86+
/-- `Contravariant` is useful to formulate succintly statements about the interactions between an
87+
action of a Type on another one and a relation on the acted-upon Type.
88+
89+
See the `ContravariantClass` doc-string for its meaning. -/
90+
def Contravariant : Prop :=
91+
∀ (m) {n₁ n₂}, r (μ m n₁) (μ m n₂) → r n₁ n₂
92+
93+
/-- Given an action `μ` of a Type `M` on a Type `N` and a relation `r` on `N`, informally, the
94+
`CovariantClass` says that "the action `μ` preserves the relation `r`."
95+
96+
More precisely, the `CovariantClass` is a class taking two Types `M N`, together with an "action"
97+
`μ : M → N → N` and a relation `r : N → N → Prop`. Its unique field `elim` is the assertion that
98+
for all `m ∈ M` and all elements `n₁, n₂ ∈ N`, if the relation `r` holds for the pair
99+
`(n₁, n₂)`, then, the relation `r` also holds for the pair `(μ m n₁, μ m n₂)`,
100+
obtained from `(n₁, n₂)` by acting upon it by `m`.
101+
102+
If `m : M` and `h : r n₁ n₂`, then `CovariantClass.elim m h : r (μ m n₁) (μ m n₂)`.
103+
-/
104+
class CovariantClass : Prop where
105+
/-- For all `m ∈ M` and all elements `n₁, n₂ ∈ N`, if the relation `r` holds for the pair
106+
`(n₁, n₂)`, then, the relation `r` also holds for the pair `(μ m n₁, μ m n₂)` -/
107+
protected elim : Covariant M N μ r
108+
109+
/-- Given an action `μ` of a Type `M` on a Type `N` and a relation `r` on `N`, informally, the
110+
`ContravariantClass` says that "if the result of the action `μ` on a pair satisfies the
111+
relation `r`, then the initial pair satisfied the relation `r`."
112+
113+
More precisely, the `ContravariantClass` is a class taking two Types `M N`, together with an
114+
"action" `μ : M → N → N` and a relation `r : N → N → Prop`. Its unique field `elim` is the
115+
assertion that for all `m ∈ M` and all elements `n₁, n₂ ∈ N`, if the relation `r` holds for the
116+
pair `(μ m n₁, μ m n₂)` obtained from `(n₁, n₂)` by acting upon it by `m`, then, the relation
117+
`r` also holds for the pair `(n₁, n₂)`.
118+
119+
If `m : M` and `h : r (μ m n₁) (μ m n₂)`, then `ContravariantClass.elim m h : r n₁ n₂`.
120+
-/
121+
class ContravariantClass : Prop where
122+
/-- For all `m ∈ M` and all elements `n₁, n₂ ∈ N`, if the relation `r` holds for the
123+
pair `(μ m n₁, μ m n₂)` obtained from `(n₁, n₂)` by acting upon it by `m`, then, the relation
124+
`r` also holds for the pair `(n₁, n₂)`. -/
125+
protected elim : Contravariant M N μ r
126+
127+
theorem rel_iff_cov [CovariantClass M N μ r] [ContravariantClass M N μ r] (m : M) {a b : N} :
128+
r (μ m a) (μ m b) ↔ r a b :=
129+
⟨ContravariantClass.elim _, CovariantClass.elim _⟩
130+
131+
section flip
132+
133+
variable {M N μ r}
134+
135+
theorem Covariant.flip (h : Covariant M N μ r) : Covariant M N μ (flip r) :=
136+
fun a _ _ hbc => h a hbc
137+
138+
theorem Contravariant.flip (h : Contravariant M N μ r) : Contravariant M N μ (flip r) :=
139+
fun a _ _ hbc => h a hbc
140+
141+
end flip
142+
143+
section Covariant
144+
145+
variable {M N μ r} [CovariantClass M N μ r]
146+
147+
theorem act_rel_act_of_rel (m : M) {a b : N} (ab : r a b) : r (μ m a) (μ m b) :=
148+
CovariantClass.elim _ ab
149+
150+
@[to_additive]
151+
theorem Group.covariant_iff_contravariant [Group N] :
152+
Covariant N N (· * ·) r ↔ Contravariant N N (· * ·) r := by
153+
refine ⟨fun h a b c bc => ?_, fun h a b c bc => ?_⟩
154+
· rw [← inv_mul_cancel_left a b, ← inv_mul_cancel_left a c]
155+
exact h a⁻¹ bc
156+
· rw [← inv_mul_cancel_left a b, ← inv_mul_cancel_left a c] at bc
157+
exact h a⁻¹ bc
158+
159+
@[to_additive]
160+
instance (priority := 100) Group.covconv [Group N] [CovariantClass N N (· * ·) r] :
161+
ContravariantClass N N (· * ·) r :=
162+
⟨Group.covariant_iff_contravariant.mp CovariantClass.elim⟩
163+
164+
-- Porting note: as at 2022-11-13, `to_additive` doesn't copy the `instance` attribute
165+
-- so we need to do it manually. I don't know how to copy the priority.
166+
attribute [instance] AddGroup.covconv
167+
168+
@[to_additive]
169+
theorem Group.covariant_swap_iff_contravariant_swap [Group N] :
170+
Covariant N N (swap (· * ·)) r ↔ Contravariant N N (swap (· * ·)) r := by
171+
refine ⟨fun h a b c bc => ?_, fun h a b c bc => ?_⟩
172+
· rw [← mul_inv_cancel_right b a, ← mul_inv_cancel_right c a]
173+
exact h a⁻¹ bc
174+
· rw [← mul_inv_cancel_right b a, ← mul_inv_cancel_right c a] at bc
175+
exact h a⁻¹ bc
176+
177+
178+
@[to_additive]
179+
instance (priority := 100) Group.covconv_swap [Group N] [CovariantClass N N (swap (· * ·)) r] :
180+
ContravariantClass N N (swap (· * ·)) r :=
181+
⟨Group.covariant_swap_iff_contravariant_swap.mp CovariantClass.elim⟩
182+
183+
attribute [instance] AddGroup.covconv_swap
184+
185+
section Trans
186+
187+
variable [Trans r r r] (m n : M) {a b c d : N}
188+
189+
-- Lemmas with 3 elements.
190+
theorem act_rel_of_rel_of_act_rel (ab : r a b) (rl : r (μ m b) c) : r (μ m a) c :=
191+
trans (act_rel_act_of_rel m ab) rl
192+
193+
theorem rel_act_of_rel_of_rel_act (ab : r a b) (rr : r c (μ m a)) : r c (μ m b) :=
194+
trans rr (act_rel_act_of_rel _ ab)
195+
196+
end Trans
197+
198+
end Covariant
199+
200+
-- Lemma with 4 elements.
201+
section MEqN
202+
203+
variable {M N μ r} {mu : N → N → N} [Trans r r r] [i : CovariantClass N N mu r]
204+
[i' : CovariantClass N N (swap mu) r] {a b c d : N}
205+
206+
theorem act_rel_act_of_rel_of_rel (ab : r a b) (cd : r c d) : r (mu a c) (mu b d) :=
207+
trans (@act_rel_act_of_rel _ _ (swap mu) r _ c _ _ ab) (act_rel_act_of_rel b cd)
208+
209+
end MEqN
210+
211+
section Contravariant
212+
213+
variable {M N μ r} [ContravariantClass M N μ r]
214+
215+
theorem rel_of_act_rel_act (m : M) {a b : N} (ab : r (μ m a) (μ m b)) : r a b :=
216+
ContravariantClass.elim _ ab
217+
218+
section Trans
219+
220+
variable [Trans r r r] (m n : M) {a b c d : N}
221+
222+
-- Lemmas with 3 elements.
223+
theorem act_rel_of_act_rel_of_rel_act_rel (ab : r (μ m a) b) (rl : r (μ m b) (μ m c)) :
224+
r (μ m a) c :=
225+
trans ab (rel_of_act_rel_act m rl)
226+
227+
theorem rel_act_of_act_rel_act_of_rel_act (ab : r (μ m a) (μ m b)) (rr : r b (μ m c)) :
228+
r a (μ m c) :=
229+
trans (rel_of_act_rel_act m ab) rr
230+
231+
end Trans
232+
233+
end Contravariant
234+
235+
section Monotone
236+
237+
variable {α : Type _} {M N μ} [Preorder α] [Preorder N]
238+
239+
variable {f : N → α}
240+
241+
/-- The partial application of a constant to a covariant operator is monotone. -/
242+
theorem Covariant.monotone_of_const [CovariantClass M N μ (· ≤ ·)] (m : M) : Monotone (μ m) :=
243+
fun _ _ ha => CovariantClass.elim m ha
244+
245+
/-- A monotone function remains monotone when composed with the partial application
246+
of a covariant operator. E.g., `∀ (m : ℕ), monotone f → monotone (λ n, f (m + n))`. -/
247+
theorem Monotone.covariant_of_const [CovariantClass M N μ (· ≤ ·)] (hf : Monotone f) (m : M) :
248+
Monotone fun n => f (μ m n) :=
249+
fun _ _ x => hf (Covariant.monotone_of_const m x)
250+
251+
/-- Same as `monotone.covariant_of_const`, but with the constant on the other side of
252+
the operator. E.g., `∀ (m : ℕ), monotone f → monotone (λ n, f (n + m))`. -/
253+
theorem Monotone.covariant_of_const' {μ : N → N → N} [CovariantClass N N (swap μ) (· ≤ ·)]
254+
(hf : Monotone f) (m : N) : Monotone fun n => f (μ n m) :=
255+
fun _ _ x => hf (@Covariant.monotone_of_const _ _ (swap μ) _ _ m _ _ x)
256+
257+
/-- Dual of `monotone.covariant_of_const` -/
258+
theorem Antitone.covariant_of_const [CovariantClass M N μ (· ≤ ·)] (hf : Antitone f) (m : M) :
259+
Antitone fun n => f (μ m n) :=
260+
hf.comp_monotone <| Covariant.monotone_of_const m
261+
262+
/-- Dual of `monotone.covariant_of_const'` -/
263+
theorem Antitone.covariant_of_const' {μ : N → N → N} [CovariantClass N N (swap μ) (· ≤ ·)]
264+
(hf : Antitone f) (m : N) : Antitone fun n => f (μ n m) :=
265+
hf.comp_monotone <| @Covariant.monotone_of_const _ _ (swap μ) _ _ m
266+
267+
end Monotone
268+
269+
theorem covariant_le_of_covariant_lt [PartialOrder N] :
270+
Covariant M N μ (· < ·) → Covariant M N μ (· ≤ ·) := by
271+
intro h a b c bc
272+
rcases le_iff_eq_or_lt.mp bc with (rfl | bc)
273+
· exact rfl.le
274+
· exact (h _ bc).le
275+
276+
theorem contravariant_lt_of_contravariant_le [PartialOrder N] :
277+
Contravariant M N μ (· ≤ ·) → Contravariant M N μ (· < ·) := by
278+
refine fun h a b c bc => lt_iff_le_and_ne.mpr ⟨h a bc.le, ?_⟩
279+
rintro rfl; exact lt_irrefl _ bc
280+
281+
theorem covariant_le_iff_contravariant_lt [LinearOrder N] :
282+
Covariant M N μ (· ≤ ·) ↔ Contravariant M N μ (· < ·) :=
283+
fun h _ _ _ bc => not_le.mp fun k => not_le.mpr bc (h _ k),
284+
fun h _ _ _ bc => not_lt.mp fun k => not_lt.mpr bc (h _ k)⟩
285+
286+
theorem covariant_lt_iff_contravariant_le [LinearOrder N] :
287+
Covariant M N μ (· < ·) ↔ Contravariant M N μ (· ≤ ·) :=
288+
fun h _ _ _ bc => not_lt.mp fun k => not_lt.mpr bc (h _ k),
289+
fun h _ _ _ bc => not_le.mp fun k => not_le.mpr bc (h _ k)⟩
290+
291+
-- Porting note: `covariant_flip_mul_iff` used to use the `IsSymmOp` typeclass from Lean 3 core.
292+
-- To avoid it, we prove the relevant lemma here.
293+
@[to_additive]
294+
lemma flip_mul [CommSemigroup N] : (flip (· * ·) : N → N → N) = (· * ·) :=
295+
funext fun a => funext fun b => mul_comm b a
296+
297+
@[to_additive]
298+
theorem covariant_flip_mul_iff [CommSemigroup N] :
299+
Covariant N N (flip (· * ·)) r ↔ Covariant N N (· * ·) r := by rw [flip_mul]
300+
301+
@[to_additive]
302+
theorem contravariant_flip_mul_iff [CommSemigroup N] :
303+
Contravariant N N (flip (· * ·)) r ↔ Contravariant N N (· * ·) r := by rw [flip_mul]
304+
305+
@[to_additive]
306+
instance contravariant_mul_lt_of_covariant_mul_le [Mul N] [LinearOrder N]
307+
[CovariantClass N N (· * ·) (· ≤ ·)] : ContravariantClass N N (· * ·) (· < ·) where
308+
elim := (covariant_le_iff_contravariant_lt N N (· * ·)).mp CovariantClass.elim
309+
310+
attribute [instance] contravariant_add_lt_of_covariant_add_le
311+
312+
@[to_additive]
313+
instance covariant_mul_lt_of_contravariant_mul_le [Mul N] [LinearOrder N]
314+
[ContravariantClass N N (· * ·) (· ≤ ·)] : CovariantClass N N (· * ·) (· < ·) where
315+
elim := (covariant_lt_iff_contravariant_le N N (· * ·)).mpr ContravariantClass.elim
316+
317+
attribute [instance] covariant_add_lt_of_contravariant_add_le
318+
319+
@[to_additive]
320+
instance covariant_swap_mul_le_of_covariant_mul_le [CommSemigroup N] [LE N]
321+
[CovariantClass N N (· * ·) (· ≤ ·)] : CovariantClass N N (swap (· * ·)) (· ≤ ·) where
322+
elim := (covariant_flip_mul_iff N (· ≤ ·)).mpr CovariantClass.elim
323+
324+
attribute [instance] covariant_swap_add_le_of_covariant_add_le
325+
326+
@[to_additive]
327+
instance contravariant_swap_mul_le_of_contravariant_mul_le [CommSemigroup N] [LE N]
328+
[ContravariantClass N N (· * ·) (· ≤ ·)] : ContravariantClass N N (swap (· * ·)) (· ≤ ·) where
329+
elim := (contravariant_flip_mul_iff N (· ≤ ·)).mpr ContravariantClass.elim
330+
331+
attribute [instance] contravariant_swap_add_le_of_contravariant_add_le
332+
333+
@[to_additive]
334+
instance contravariant_swap_mul_lt_of_contravariant_mul_lt [CommSemigroup N] [LT N]
335+
[ContravariantClass N N (· * ·) (· < ·)] : ContravariantClass N N (swap (· * ·)) (· < ·) where
336+
elim := (contravariant_flip_mul_iff N (· < ·)).mpr ContravariantClass.elim
337+
338+
attribute [instance] contravariant_swap_add_lt_of_contravariant_add_lt
339+
340+
@[to_additive]
341+
instance covariant_swap_mul_lt_of_covariant_mul_lt [CommSemigroup N] [LT N]
342+
[CovariantClass N N (· * ·) (· < ·)] : CovariantClass N N (swap (· * ·)) (· < ·) where
343+
elim := (covariant_flip_mul_iff N (· < ·)).mpr CovariantClass.elim
344+
345+
attribute [instance] covariant_swap_add_lt_of_covariant_add_lt
346+
347+
@[to_additive]
348+
instance LeftCancelSemigroup.covariant_mul_lt_of_covariant_mul_le [LeftCancelSemigroup N]
349+
[PartialOrder N] [CovariantClass N N (· * ·) (· ≤ ·)] :
350+
CovariantClass N N (· * ·) (· < ·) where
351+
elim a b c bc := by
352+
cases' lt_iff_le_and_ne.mp bc with bc cb
353+
exact lt_iff_le_and_ne.mpr ⟨CovariantClass.elim a bc, (mul_ne_mul_right a).mpr cb⟩
354+
355+
attribute [instance] AddLeftCancelSemigroup.covariant_add_lt_of_covariant_add_le
356+
357+
@[to_additive]
358+
instance RightCancelSemigroup.covariant_swap_mul_lt_of_covariant_swap_mul_le
359+
[RightCancelSemigroup N] [PartialOrder N] [CovariantClass N N (swap (· * ·)) (· ≤ ·)] :
360+
CovariantClass N N (swap (· * ·)) (· < ·) where
361+
elim a b c bc := by
362+
cases' lt_iff_le_and_ne.mp bc with bc cb
363+
exact lt_iff_le_and_ne.mpr ⟨CovariantClass.elim a bc, (mul_ne_mul_left a).mpr cb⟩
364+
365+
attribute [instance] AddRightCancelSemigroup.covariant_swap_add_lt_of_covariant_swap_add_le
366+
367+
@[to_additive]
368+
instance LeftCancelSemigroup.contravariant_mul_le_of_contravariant_mul_lt [LeftCancelSemigroup N]
369+
[PartialOrder N] [ContravariantClass N N (· * ·) (· < ·)] :
370+
ContravariantClass N N (· * ·) (· ≤ ·) where
371+
elim a b c bc := by
372+
cases' le_iff_eq_or_lt.mp bc with h h
373+
· exact ((mul_right_inj a).mp h).le
374+
· exact (ContravariantClass.elim _ h).le
375+
376+
attribute [instance] AddLeftCancelSemigroup.contravariant_add_le_of_contravariant_add_lt
377+
378+
@[to_additive]
379+
instance RightCancelSemigroup.contravariant_swap_mul_le_of_contravariant_swap_mul_lt
380+
[RightCancelSemigroup N] [PartialOrder N] [ContravariantClass N N (swap (· * ·)) (· < ·)] :
381+
ContravariantClass N N (swap (· * ·)) (· ≤ ·) where
382+
elim a b c bc := by
383+
cases' le_iff_eq_or_lt.mp bc with h h
384+
· exact ((mul_left_inj a).mp h).le
385+
· exact (ContravariantClass.elim _ h).le
386+
387+
attribute [instance] AddRightCancelSemigroup.contravariant_swap_add_le_of_contravariant_swap_add_lt
388+
389+
end Variants

0 commit comments

Comments
 (0)