Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
2f3869e
feat: unfold-boundaries in `to_dual`
JovanGerb Dec 4, 2025
6850a52
make linters happy
JovanGerb Dec 5, 2025
70bb4a5
some improvements
JovanGerb Dec 5, 2025
94a72a1
.
JovanGerb Dec 5, 2025
8d2fe98
improved UI
JovanGerb Dec 15, 2025
2152b67
Merge branch 'master' into Jovan-to_dual-unfold
JovanGerb Dec 15, 2025
5862642
missing `partial`
JovanGerb Dec 15, 2025
4360943
adaptations
JovanGerb Dec 15, 2025
43dd223
fix the problem with OrderEmbedding
JovanGerb Dec 18, 2025
51ac4ab
Merge branch 'master' into Jovan-to_dual-unfold
JovanGerb Dec 18, 2025
782749b
Merge branch 'master' into Jovan-to_dual-unfold
JovanGerb Dec 19, 2025
cc31e39
.
JovanGerb Dec 19, 2025
d4ff223
golf and docs
JovanGerb Dec 19, 2025
74a71e2
fix
JovanGerb Dec 19, 2025
8c173d4
improvements
JovanGerb Dec 19, 2025
de2f276
Merge branch 'master' into Jovan-to_dual-unfold
JovanGerb Dec 19, 2025
e910c90
withExporting
JovanGerb Dec 20, 2025
e31116b
add tracing
JovanGerb Dec 20, 2025
1baf799
doc-string
JovanGerb Dec 20, 2025
a70ee1a
add tests
JovanGerb Dec 20, 2025
9f1f939
apply to `IsThin`
JovanGerb Dec 20, 2025
e1da64a
add more tests
JovanGerb Dec 20, 2025
cb0a6a7
clean up documentation
JovanGerb Dec 22, 2025
739fc74
show that is also works for `GaloisConnection`
JovanGerb Dec 23, 2025
c440be2
refactor(translate): merge `expand` into `applyReplacementFun`
JovanGerb Dec 23, 2025
193aee4
Revert "refactor(translate): merge `expand` into `applyReplacementFun`"
JovanGerb Dec 23, 2025
d7e5915
Merge branch 'master' into Jovan-to_dual-unfold
JovanGerb Dec 23, 2025
26ef421
Merge branch 'master' into Jovan-to_dual-unfold
JovanGerb Dec 25, 2025
df64221
fix beta reduction problem?
JovanGerb Dec 26, 2025
4014a6b
fix decidable instances
JovanGerb Dec 26, 2025
04cdf03
Merge branch 'master' into Jovan-to_dual-unfold
JovanGerb Jan 3, 2026
ac14e89
Merge branch 'master' into Jovan-to_dual-unfold
JovanGerb Jan 3, 2026
68289ee
Merge branch 'master' into Jovan-to_dual-unfold
JovanGerb Jan 8, 2026
69074ec
Merge branch 'master' into Jovan-to_dual-unfold
JovanGerb Jan 14, 2026
f13f590
Merge branch 'master' into Jovan-to_dual-unfold
JovanGerb Jan 14, 2026
221a8a7
.
JovanGerb Jan 14, 2026
e9532f8
clean up
JovanGerb Jan 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Mathlib.lean
Original file line number Diff line number Diff line change
Expand Up @@ -6807,6 +6807,7 @@ public import Mathlib.Tactic.Translate.Core
public import Mathlib.Tactic.Translate.GuessName
public import Mathlib.Tactic.Translate.ToAdditive
public import Mathlib.Tactic.Translate.ToDual
public import Mathlib.Tactic.Translate.UnfoldBoundary
public import Mathlib.Tactic.TryThis
public import Mathlib.Tactic.TypeCheck
public import Mathlib.Tactic.TypeStar
Expand Down
4 changes: 2 additions & 2 deletions Mathlib/Combinatorics/Quiver/Basic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ instance emptyQuiver (V : Type u) : Quiver.{u} (Empty V) := ⟨fun _ _ => PEmpty
theorem empty_arrow {V : Type u} (a b : Empty V) : (a ⟶ b) = PEmpty := rfl

/-- A quiver is thin if it has no parallel arrows. -/
@[to_dual IsThin' /-- `isThin'` is equivalent to `IsThin`.
It is used by `@[to_dual]` to be able to translate `IsThin`. -/]
abbrev IsThin (V : Type u) [Quiver V] : Prop := ∀ a b : V, Subsingleton (a ⟶ b)

to_dual_insert_cast_fun IsThin := fun inst a b ↦ inst b a, fun inst a b ↦ inst b a


section

Expand Down
2 changes: 0 additions & 2 deletions Mathlib/Order/Basic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -930,11 +930,9 @@ instance preorder [Preorder α] (p : α → Prop) : Preorder (Subtype p) :=
instance partialOrder [PartialOrder α] (p : α → Prop) : PartialOrder (Subtype p) :=
PartialOrder.lift (fun (a : Subtype p) ↦ (a : α)) Subtype.coe_injective

@[to_dual decidableLE']
instance decidableLE [Preorder α] [h : DecidableLE α] {p : α → Prop} :
DecidableLE (Subtype p) := fun a b ↦ h a b

@[to_dual decidableLT']
instance decidableLT [Preorder α] [h : DecidableLT α] {p : α → Prop} :
DecidableLT (Subtype p) := fun a b ↦ h a b

Expand Down
25 changes: 19 additions & 6 deletions Mathlib/Order/Cover.lean
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ section Preorder

variable [Preorder α] [Preorder β] {a b c : α}

@[to_dual self]
theorem WCovBy.le (h : a ⩿ b) : a ≤ b :=
h.1

Expand All @@ -46,20 +47,25 @@ theorem WCovBy.refl (a : α) : a ⩿ a :=

@[simp] lemma WCovBy.rfl : a ⩿ a := WCovBy.refl a

@[to_dual wcovBy']
protected theorem Eq.wcovBy (h : a = b) : a ⩿ b :=
h ▸ WCovBy.rfl

@[to_dual self]
theorem wcovBy_of_le_of_le (h1 : a ≤ b) (h2 : b ≤ a) : a ⩿ b :=
⟨h1, fun _ hac hcb => (hac.trans hcb).not_ge h2⟩

@[to_dual self]
alias LE.le.wcovBy_of_le := wcovBy_of_le_of_le

theorem AntisymmRel.wcovBy (h : AntisymmRel (· ≤ ·) a b) : a ⩿ b :=
wcovBy_of_le_of_le h.1 h.2

@[to_dual self]
theorem WCovBy.wcovBy_iff_le (hab : a ⩿ b) : b ⩿ a ↔ b ≤ a :=
⟨fun h => h.le, fun h => h.wcovBy_of_le hab.le⟩

@[to_dual wcovBy_of_eq_or_eq']
theorem wcovBy_of_eq_or_eq (hab : a ≤ b) (h : ∀ c, a ≤ c → c ≤ b → c = a ∨ c = b) : a ⩿ b :=
⟨hab, fun c ha hb => (h c ha.le hb.le).elim ha.ne' hb.ne⟩

Expand All @@ -76,52 +82,59 @@ theorem wcovBy_congr_right (hab : AntisymmRel (· ≤ ·) a b) : c ⩿ a ↔ c
⟨fun h => h.trans_antisymm_rel hab, fun h => h.trans_antisymm_rel hab.symm⟩

/-- If `a ≤ b`, then `b` does not cover `a` iff there's an element in between. -/
@[to_dual not_wcovBy_iff']
theorem not_wcovBy_iff (h : a ≤ b) : ¬a ⩿ b ↔ ∃ c, a < c ∧ c < b := by
simp_rw [WCovBy, h, true_and, not_forall, exists_prop, not_not]

@[to_dual stdRefl']
instance WCovBy.stdRefl : @Std.Refl α (· ⩿ ·) :=
⟨WCovBy.refl⟩

@[to_dual self]
theorem WCovBy.Ioo_eq (h : a ⩿ b) : Ioo a b = ∅ :=
eq_empty_iff_forall_notMem.2 fun _ hx => h.2 hx.1 hx.2

@[to_dual self]
theorem wcovBy_iff_Ioo_eq : a ⩿ b ↔ a ≤ b ∧ Ioo a b = ∅ :=
and_congr_right' <| by simp [eq_empty_iff_forall_notMem]

@[to_dual of_le_of_le']
lemma WCovBy.of_le_of_le (hac : a ⩿ c) (hab : a ≤ b) (hbc : b ≤ c) : b ⩿ c :=
⟨hbc, fun _x hbx hxc ↦ hac.2 (hab.trans_lt hbx) hxc⟩

lemma WCovBy.of_le_of_le' (hac : a ⩿ c) (hab : a ≤ b) (hbc : b ≤ c) : a ⩿ b :=
⟨hab, fun _x hax hxb ↦ hac.2 hax <| hxb.trans_le hbc⟩

@[to_dual self]
theorem WCovBy.of_image (f : α ↪o β) (h : f a ⩿ f b) : a ⩿ b :=
⟨f.le_iff_le.mp h.le, fun _ hac hcb => h.2 (f.lt_iff_lt.mpr hac) (f.lt_iff_lt.mpr hcb)⟩

@[to_dual self]
theorem WCovBy.image (f : α ↪o β) (hab : a ⩿ b) (h : (range f).OrdConnected) : f a ⩿ f b := by
refine ⟨f.monotone hab.le, fun c ha hb => ?_⟩
obtain ⟨c, rfl⟩ := h.out (mem_range_self _) (mem_range_self _) ⟨ha.le, hb.le⟩
rw [f.lt_iff_lt] at ha hb
exact hab.2 ha hb

@[to_dual self]
theorem Set.OrdConnected.apply_wcovBy_apply_iff (f : α ↪o β) (h : (range f).OrdConnected) :
f a ⩿ f b ↔ a ⩿ b :=
⟨fun h2 => h2.of_image f, fun hab => hab.image f h⟩

@[simp]
@[simp, to_dual self]
theorem apply_wcovBy_apply_iff {E : Type*} [EquivLike E α β] [OrderIsoClass E α β] (e : E) :
e a ⩿ e b ↔ a ⩿ b :=
(ordConnected_range (e : α ≃o β)).apply_wcovBy_apply_iff ((e : α ≃o β) : α ↪o β)

@[simp]
@[simp, to_dual self]
theorem toDual_wcovBy_toDual_iff : toDual b ⩿ toDual a ↔ a ⩿ b :=
and_congr_right' <| forall_congr' fun _ => forall_swap

@[simp]
@[simp, to_dual self]
theorem ofDual_wcovBy_ofDual_iff {a b : αᵒᵈ} : ofDual a ⩿ ofDual b ↔ b ⩿ a :=
and_congr_right' <| forall_congr' fun _ => forall_swap

@[to_dual self]
alias ⟨_, WCovBy.toDual⟩ := toDual_wcovBy_toDual_iff

@[to_dual self]
alias ⟨_, WCovBy.ofDual⟩ := ofDual_wcovBy_ofDual_iff

@[deprecated (since := "2025-11-07")] alias OrderEmbedding.wcovBy_of_apply := WCovBy.of_image
Expand Down
6 changes: 0 additions & 6 deletions Mathlib/Order/Defs/LinearOrder.lean
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,6 @@ attribute [instance 900] LinearOrder.toDecidableLT
attribute [instance 900] LinearOrder.toDecidableLE
attribute [instance 900] LinearOrder.toDecidableEq

@[to_dual existing toDecidableLT, inherit_doc toDecidableLT]
def LinearOrder.toDecidableLT' : DecidableLT' α := fun a b => toDecidableLT b a

@[to_dual existing toDecidableLE, inherit_doc toDecidableLE]
def LinearOrder.toDecidableLE' : DecidableLE' α := fun a b => toDecidableLE b a

instance : Std.IsLinearOrder α where
le_total := LinearOrder.le_total

Expand Down
11 changes: 4 additions & 7 deletions Mathlib/Order/Defs/PartialOrder.lean
Original file line number Diff line number Diff line change
Expand Up @@ -132,19 +132,18 @@ instance instTransGTGE : @Trans α α α GT.gt GE.ge GT.gt := ⟨lt_of_lt_of_le'
instance instTransGEGT : @Trans α α α GE.ge GT.gt GT.gt := ⟨lt_of_le_of_lt'⟩

/-- `<` is decidable if `≤` is. -/
@[to_dual decidableLT'OfDecidableLE' /-- `<` is decidable if `≤` is. -/]
def decidableLTOfDecidableLE [DecidableLE α] : DecidableLT α :=
fun _ _ => decidable_of_iff _ lt_iff_le_not_ge.symm

@[deprecated (since := "2025-12-09")] alias decidableGTOfDecidableGE := decidableLT'OfDecidableLE'

/-- `WCovBy a b` means that `a = b` or `b` covers `a`.
This means that `a ≤ b` and there is no element in between. This is denoted `a ⩿ b`.
-/
@[to_dual self (reorder := 3 4)]
def WCovBy (a b : α) : Prop :=
a ≤ b ∧ ∀ ⦃c⦄, a < c → ¬c < b

to_dual_insert_cast WCovBy := by grind

@[inherit_doc]
infixl:50 " ⩿ " => WCovBy

Expand All @@ -154,6 +153,8 @@ between. This is denoted `a ⋖ b`. -/
def CovBy {α : Type*} [LT α] (a b : α) : Prop :=
a < b ∧ ∀ ⦃c⦄, a < c → ¬c < b

to_dual_insert_cast CovBy := by grind

@[inherit_doc]
infixl:50 " ⋖ " => CovBy

Expand Down Expand Up @@ -197,16 +198,12 @@ lemma lt_of_le_of_ne : a ≤ b → a ≠ b → a < b := fun h₁ h₂ =>
lt_of_le_not_ge h₁ <| mt (le_antisymm h₁) h₂

/-- Equality is decidable if `≤` is. -/
@[to_dual decidableEqOfDecidableLE' /-- Equality is decidable if `≤` is. -/]
def decidableEqOfDecidableLE [DecidableLE α] : DecidableEq α
| a, b =>
if hab : a ≤ b then
if hba : b ≤ a then isTrue (le_antisymm hab hba) else isFalse fun heq => hba (heq ▸ le_refl _)
else isFalse fun heq => hab (heq ▸ le_refl _)

@[deprecated (since := "2025-12-09")] alias decidableEqofDecidableGE := decidableEqOfDecidableLE'
@[deprecated (since := "2025-12-09")] alias decidableEqofDecidableLE' := decidableEqOfDecidableLE'

-- See Note [decidable namespace]
@[to_dual Decidable.lt_or_eq_of_le']
protected lemma Decidable.lt_or_eq_of_le [DecidableLE α] (hab : a ≤ b) : a < b ∨ a = b :=
Expand Down
66 changes: 19 additions & 47 deletions Mathlib/Order/GaloisConnection/Defs.lean
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,24 @@ variable {α : Type u} {β : Type v} {γ : Type w} {ι : Sort x} {κ : ι → So
/-- A Galois connection is a pair of functions `l` and `u` satisfying
`l a ≤ b ↔ a ≤ u b`. They are special cases of adjoint functors in category theory,
but do not depend on the category theory library in mathlib. -/
@[to_dual self (reorder := α β, 3 4, l u)]
def GaloisConnection [Preorder α] [Preorder β] (l : α → β) (u : β → α) :=
∀ a b, l a ≤ b ↔ a ≤ u b

to_dual_insert_cast GaloisConnection := by grind

namespace GaloisConnection

section

variable [Preorder α] [Preorder β] {l : α → β} {u : β → α}

@[to_dual self (reorder := α β, 3 4, l u, hu hl, hul hlu)]
theorem monotone_intro (hu : Monotone u) (hl : Monotone l) (hul : ∀ a, a ≤ u (l a))
(hlu : ∀ a, l (u a) ≤ a) : GaloisConnection l u := fun _ _ =>
⟨fun h => (hul _).trans (hu h), fun h => (hl h).trans (hlu _)⟩

@[to_dual self]
protected theorem dual {l : α → β} {u : β → α} (gc : GaloisConnection l u) :
GaloisConnection (OrderDual.toDual ∘ u ∘ OrderDual.ofDual)
(OrderDual.toDual ∘ l ∘ OrderDual.ofDual) :=
Expand All @@ -59,57 +64,55 @@ protected theorem dual {l : α → β} {u : β → α} (gc : GaloisConnection l
variable (gc : GaloisConnection l u)
include gc

@[to_dual le_iff_le']
theorem le_iff_le {a : α} {b : β} : l a ≤ b ↔ a ≤ u b :=
gc _ _

@[to_dual le_u]
theorem l_le {a : α} {b : β} : a ≤ u b → l a ≤ b :=
(gc _ _).mpr

theorem le_u {a : α} {b : β} : l a ≤ b → a ≤ u b :=
(gc _ _).mp

@[to_dual l_u_le]
theorem le_u_l (a) : a ≤ u (l a) :=
gc.le_u <| le_rfl

theorem l_u_le (a) : l (u a) ≤ a :=
gc.l_le <| le_rfl

@[to_dual]
theorem monotone_u : Monotone u := fun a _ H => gc.le_u ((gc.l_u_le a).trans H)

theorem monotone_l : Monotone l :=
gc.dual.monotone_u.dual

/-- If `(l, u)` is a Galois connection, then the relation `x ≤ u (l y)` is a transitive relation.
If `l` is a closure operator (`Submodule.span`, `Subgroup.closure`, ...) and `u` is the coercion to
`Set`, this reads as "if `U` is in the closure of `V` and `V` is in the closure of `W` then `U` is
in the closure of `W`". -/
@[to_dual l_u_le_trans]
theorem le_u_l_trans {x y z : α} (hxy : x ≤ u (l y)) (hyz : y ≤ u (l z)) : x ≤ u (l z) :=
hxy.trans (gc.monotone_u <| gc.l_le hyz)

theorem l_u_le_trans {x y z : β} (hxy : l (u x) ≤ y) (hyz : l (u y) ≤ z) : l (u x) ≤ z :=
(gc.monotone_l <| gc.le_u hxy).trans hyz

end

section PartialOrder

variable [PartialOrder α] [Preorder β] {l : α → β} {u : β → α} (gc : GaloisConnection l u)
include gc

@[to_dual]
theorem u_l_u_eq_u (b : β) : u (l (u b)) = u b :=
(gc.monotone_u (gc.l_u_le _)).antisymm (gc.le_u_l _)

@[to_dual]
theorem u_l_u_eq_u' : u ∘ l ∘ u = u :=
funext gc.u_l_u_eq_u

@[to_dual]
theorem u_unique {l' : α → β} {u' : β → α} (gc' : GaloisConnection l' u') (hl : ∀ a, l a = l' a)
{b : β} : u b = u' b :=
le_antisymm (gc'.le_u <| hl (u b) ▸ gc.l_u_le _) (gc.le_u <| (hl (u' b)).symm ▸ gc'.l_u_le _)

/-- If there exists a `b` such that `a = u a`, then `b = l a` is one such element. -/
@[to_dual /-- If there exists an `a` such that `b = l a`, then `a = u b` is one such element. -/]
theorem exists_eq_u (a : α) : (∃ b : β, a = u b) ↔ a = u (l a) :=
⟨fun ⟨_, hS⟩ => hS.symm ▸ (gc.u_l_u_eq_u _).symm, fun HI => ⟨_, HI⟩⟩

@[to_dual]
theorem u_eq {z : α} {y : β} : u y = z ↔ ∀ x, x ≤ z ↔ l x ≤ y := by
constructor
· rintro rfl x
Expand All @@ -119,60 +122,29 @@ theorem u_eq {z : α} {y : β} : u y = z ↔ ∀ x, x ≤ z ↔ l x ≤ y := by

end PartialOrder

section PartialOrder

variable [Preorder α] [PartialOrder β] {l : α → β} {u : β → α} (gc : GaloisConnection l u)
include gc

theorem l_u_l_eq_l (a : α) : l (u (l a)) = l a := gc.dual.u_l_u_eq_u _

theorem l_u_l_eq_l' : l ∘ u ∘ l = l := funext gc.l_u_l_eq_l

theorem l_unique {l' : α → β} {u' : β → α} (gc' : GaloisConnection l' u') (hu : ∀ b, u b = u' b)
{a : α} : l a = l' a :=
gc.dual.u_unique gc'.dual hu

/-- If there exists an `a` such that `b = l a`, then `a = u b` is one such element. -/
theorem exists_eq_l (b : β) : (∃ a : α, b = l a) ↔ b = l (u b) := gc.dual.exists_eq_u _

theorem l_eq {x : α} {z : β} : l x = z ↔ ∀ y, z ≤ y ↔ x ≤ u y := gc.dual.u_eq

end PartialOrder

section OrderTop

variable [PartialOrder α] [Preorder β] [OrderTop α]

@[to_dual]
theorem u_eq_top {l : α → β} {u : β → α} (gc : GaloisConnection l u) {x} : u x = ⊤ ↔ l ⊤ ≤ x :=
top_le_iff.symm.trans gc.le_iff_le.symm

@[to_dual]
theorem u_top [OrderTop β] {l : α → β} {u : β → α} (gc : GaloisConnection l u) : u ⊤ = ⊤ :=
gc.u_eq_top.2 le_top

@[to_dual]
theorem u_l_top {l : α → β} {u : β → α} (gc : GaloisConnection l u) : u (l ⊤) = ⊤ :=
gc.u_eq_top.mpr le_rfl

end OrderTop

section OrderBot

variable [Preorder α] [PartialOrder β] [OrderBot β]

theorem l_eq_bot {l : α → β} {u : β → α} (gc : GaloisConnection l u) {x} : l x = ⊥ ↔ x ≤ u ⊥ :=
gc.dual.u_eq_top

theorem l_bot [OrderBot α] {l : α → β} {u : β → α} (gc : GaloisConnection l u) : l ⊥ = ⊥ :=
gc.dual.u_top

theorem l_u_bot {l : α → β} {u : β → α} (gc : GaloisConnection l u) : l (u ⊥) = ⊥ :=
gc.l_eq_bot.mpr le_rfl

end OrderBot

section LinearOrder

variable [LinearOrder α] [LinearOrder β] {l : α → β} {u : β → α}

@[to_dual lt_iff_lt']
theorem lt_iff_lt (gc : GaloisConnection l u) {a : α} {b : β} : b < l a ↔ u b < a :=
lt_iff_lt_of_le_iff_le (gc a b)

Expand Down
Loading
Loading