Skip to content

Commit

Permalink
feat(data/equiv/basic): add a computable version of equiv.set.range (#…
Browse files Browse the repository at this point in the history
…6821)

If a left-inverse of `f` is known, it can be used to construct the equiv both computably and with control over definitional reduction.

This adds the definition `equiv.set.range_of_left_inverse` to mirror `linear_equiv.of_left_inverse` and `ring_equiv.of_left_inverse`.
  • Loading branch information
eric-wieser committed Mar 25, 2021
1 parent c3034c2 commit 5a72daf
Showing 1 changed file with 29 additions and 8 deletions.
37 changes: 29 additions & 8 deletions src/data/equiv/basic.lean
Expand Up @@ -1667,21 +1667,42 @@ begin
simp [equiv.set.image, equiv.set.image_of_inj_on, hf.eq_iff, this],
end

/-- If `f : α → β` has a left-inverse when `α` is nonempty, then `α` is computably equivalent to the
range of `f`.
While awkward, the `nonempty α` hypothesis on `f_inv` and `hf` allows this to be used when `α` is
empty too. This hypothesis is absent on analogous definitions on stronger `equiv`s like
`linear_equiv.of_left_inverse` and `ring_equiv.of_left_inverse` as their typeclass assumptions
are already sufficient to ensure non-emptiness. -/
@[simps]
def range_of_left_inverse {α β : Sort*}
(f : α → β) (f_inv : nonempty α → β → α) (hf : Π h : nonempty α, left_inverse (f_inv h) f) :
α ≃ set.range f :=
{ to_fun := λ a, ⟨f a, a, rfl⟩,
inv_fun := λ b, f_inv (let ⟨a, _⟩ := b.2 in ⟨a⟩) b,
left_inv := λ a, hf ⟨a⟩ a,
right_inv := λ ⟨b, a, ha⟩, subtype.eq $ show f (f_inv ⟨a⟩ b) = b,
from eq.trans (congr_arg f $ by exact ha ▸ (hf _ a)) ha }

/-- If `f : α → β` has a left-inverse, then `α` is computably equivalent to the range of `f`.
Note that if `α` is empty, no such `f_inv` exists and so this definition can't be used, unlike
the stronger but less convenient `equiv.set.range_of_left_inverse`. -/
abbreviation range_of_left_inverse' {α β : Sort*}
(f : α → β) (f_inv : β → α) (hf : left_inverse f_inv f) :
α ≃ set.range f :=
range_of_left_inverse f (λ _, f_inv) (λ _, hf)

/-- If `f : α → β` is an injective function, then `α` is equivalent to the range of `f`. -/
@[simps apply]
protected noncomputable def range {α β} (f : α → β) (H : injective f) :
α ≃ range f :=
{ to_fun := λ x, ⟨f x, mem_range_self _⟩,
inv_fun := λ x, classical.some x.2,
left_inv := λ x, H (classical.some_spec (show f x ∈ range f, from mem_range_self _)),
right_inv := λ x, subtype.eq $ classical.some_spec x.2 }
equiv.set.range_of_left_inverse f
(λ h, by exactI function.inv_fun f) (λ h, by exactI function.left_inverse_inv_fun H)

theorem apply_range_symm {α β} (f : α → β) (H : injective f) (b : range f) :
f ((set.range f H).symm b) = b :=
begin
conv_rhs { rw ←((set.range f H).right_inv b), },
simp,
end
subtype.ext_iff.1 $ (set.range f H).apply_symm_apply b

/-- If `α` is equivalent to `β`, then `set α` is equivalent to `set β`. -/
@[simps]
Expand Down

0 comments on commit 5a72daf

Please sign in to comment.