Skip to content

Commit

Permalink
chore(data/finsupp): lemmas about map_range and map_domain (#6976)
Browse files Browse the repository at this point in the history
This proves some functorial properties:
* `finsupp.map_range_id`
* `finsupp.map_range_comp`

Adds the new definitions to match `finsupp.map_range.add_monoid_hom`, and uses them to golf some proofs:
* `finsupp.map_range.zero_hom`, which is `map_domain` as a `zero_hom`
* `finsupp.map_range.add_equiv`, which is `map_range` as an `add_equiv`
* `finsupp.map_range.linear_map`, which is `map_range` as a `linear_map`
* `finsupp.map_range.linear_equiv`, which is `map_range` as a `linear_equiv`
* `finsupp.map_domain.add_monoid_hom`, which is `map_domain` as an `add_monoid_hom`

Shows the functorial properties of these bundled definitions:
* `finsupp.map_range.zero_hom_id`, `finsupp.map_range.zero_hom_comp`
* `finsupp.map_range.add_monoid_hom_id`, `finsupp.map_range.add_monoid_hom_comp`
* `finsupp.map_range.add_equiv_refl`, `finsupp.map_range.add_equiv_trans`
* `finsupp.map_range.linear_map_id`, `finsupp.map_range.linear_map_comp`
* `finsupp.map_range.linear_equiv_refl`, `finsupp.map_range.linear_equiv_trans`
* `finsupp.map_domain.add_monoid_hom_id`, `finsupp.map_domain.add_monoid_hom_comp`

And shows that `map_range` and `map_domain` commute when the range-map preserves addition:
* `finsupp.map_domain_map_range`
  • Loading branch information
eric-wieser committed Apr 2, 2021
1 parent 6e5c07b commit 394719f
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 32 deletions.
151 changes: 139 additions & 12 deletions src/data/finsupp/basic.lean
Expand Up @@ -398,10 +398,20 @@ end of_support_finite
/-! ### Declarations about `map_range` -/

section map_range
variables [has_zero M] [has_zero N]
variables [has_zero M] [has_zero N] [has_zero P]

/-- The composition of `f : M → N` and `g : α →₀ M` is
`map_range f hf g : α →₀ N`, well-defined when `f 0 = 0`. -/
`map_range f hf g : α →₀ N`, well-defined when `f 0 = 0`.
This preserves the structure on `f`, and exists in various bundled forms for when `f` is itself
bundled:
* `finsupp.map_range.zero_hom`
* `finsupp.map_range.add_monoid_hom`
* `finsupp.map_range.add_equiv`
* `finsupp.map_range.linear_map`
* `finsupp.map_range.linear_equiv`
-/
def map_range (f : M → N) (hf : f 0 = 0) (g : α →₀ M) : α →₀ N :=
on_finset g.support (f ∘ g) $
assume a, by rw [mem_support_iff, not_imp_not]; exact λ H, (congr_arg f H).trans hf
Expand All @@ -413,6 +423,14 @@ rfl
@[simp] lemma map_range_zero {f : M → N} {hf : f 0 = 0} : map_range f hf (0 : α →₀ M) = 0 :=
ext $ λ a, by simp only [hf, zero_apply, map_range_apply]

@[simp] lemma map_range_id (g : α →₀ M) : map_range id rfl g = g :=
ext $ λ _, rfl

lemma map_range_comp
(f : N → P) (hf : f 0 = 0) (f₂ : M → N) (hf₂ : f₂ 0 = 0) (h : (f ∘ f₂) 0 = 0) (g : α →₀ M) :
map_range (f ∘ f₂) h g = map_range f hf (map_range f₂ hf₂ g) :=
ext $ λ _, rfl

lemma support_map_range {f : M → N} {hf : f 0 = 0} {g : α →₀ M} :
(map_range f hf g).support ⊆ g.support :=
support_on_finset_subset
Expand Down Expand Up @@ -1144,24 +1162,91 @@ lemma multiset_sum_sum [has_zero M] [add_comm_monoid N] {f : α →₀ M} {h :
(f.support.sum_hom multiset.sum).symm

section map_range
variables
[add_comm_monoid M] [add_comm_monoid N] (f : M →+ N)

section zero_hom
variables [has_zero M] [has_zero N] [has_zero P]

/-- Composition with a fixed zero-preserving homomorphism is itself an zero-preserving homomorphism
on functions. -/
@[simps]
def map_range.zero_hom (f : zero_hom M N) : zero_hom (α →₀ M) (α →₀ N) :=
{ to_fun := (map_range f f.map_zero : (α →₀ M) → (α →₀ N)),
map_zero' := map_range_zero }

@[simp]
lemma map_range.zero_hom_id :
map_range.zero_hom (zero_hom.id M) = zero_hom.id (α →₀ M) := zero_hom.ext map_range_id

lemma map_range.zero_hom_comp (f : zero_hom N P) (f₂ : zero_hom M N) :
(map_range.zero_hom (f.comp f₂) : zero_hom (α →₀ _) _) =
(map_range.zero_hom f).comp (map_range.zero_hom f₂) :=
zero_hom.ext $ map_range_comp _ _ _ _ _

end zero_hom

section add_monoid_hom
variables [add_comm_monoid M] [add_comm_monoid N] [add_comm_monoid P]

/--
Composition with a fixed additive homomorphism is itself an additive homomorphism on functions.
-/
def map_range.add_monoid_hom : (α →₀ M) →+ (α →₀ N) :=
@[simps]
def map_range.add_monoid_hom (f : M →+ N) : (α →₀ M) →+ (α →₀ N) :=
{ to_fun := (map_range f f.map_zero : (α →₀ M) → (α →₀ N)),
map_zero' := map_range_zero,
map_add' := λ a b, map_range_add f.map_add _ _ }

lemma map_range_multiset_sum (m : multiset (α →₀ M)) :
@[simp]
lemma map_range.add_monoid_hom_id :
map_range.add_monoid_hom (add_monoid_hom.id M) = add_monoid_hom.id (α →₀ M) :=
add_monoid_hom.ext map_range_id

lemma map_range.add_monoid_hom_comp (f : N →+ P) (f₂ : M →+ N) :
(map_range.add_monoid_hom (f.comp f₂) : (α →₀ _) →+ _) =
(map_range.add_monoid_hom f).comp (map_range.add_monoid_hom f₂) :=
add_monoid_hom.ext $ map_range_comp _ _ _ _ _

lemma map_range_multiset_sum (f : M →+ N) (m : multiset (α →₀ M)) :
map_range f f.map_zero m.sum = (m.map $ λx, map_range f f.map_zero x).sum :=
(m.sum_hom (map_range.add_monoid_hom f)).symm
(map_range.add_monoid_hom f : (α →₀ _) →+ _).map_multiset_sum _

lemma map_range_finset_sum (s : finset ι) (g : ι → (α →₀ M)) :
lemma map_range_finset_sum (f : M →+ N) (s : finset ι) (g : ι → (α →₀ M)) :
map_range f f.map_zero (∑ x in s, g x) = ∑ x in s, map_range f f.map_zero (g x) :=
by rw [finset.sum.equations._eqn_1, map_range_multiset_sum, multiset.map_map]; refl
(map_range.add_monoid_hom f : (α →₀ _) →+ _).map_sum _ _


/-- `finsupp.map_range.add_monoid_hom` as an equiv. -/
@[simps apply]
def map_range.add_equiv (f : M ≃+ N) : (α →₀ M) ≃+ (α →₀ N) :=
{ to_fun := (map_range f f.map_zero : (α →₀ M) → (α →₀ N)),
inv_fun := (map_range f.symm f.symm.map_zero : (α →₀ N) → (α →₀ M)),
left_inv := λ x, begin
rw ←map_range_comp _ _ _ _; simp_rw add_equiv.symm_comp_self,
{ exact map_range_id _ },
{ refl },
end,
right_inv := λ x, begin
rw ←map_range_comp _ _ _ _; simp_rw add_equiv.self_comp_symm,
{ exact map_range_id _ },
{ refl },
end,
..(map_range.add_monoid_hom f.to_add_monoid_hom) }

@[simp]
lemma map_range.add_equiv_refl :
map_range.add_equiv (add_equiv.refl M) = add_equiv.refl (α →₀ M) :=
add_equiv.ext map_range_id

lemma map_range.add_equiv_trans (f : M ≃+ N) (f₂ : N ≃+ P) :
(map_range.add_equiv (f.trans f₂) : (α →₀ _) ≃+ _) =
(map_range.add_equiv f).trans (map_range.add_equiv f₂) :=
add_equiv.ext $ map_range_comp _ _ _ _ _

lemma map_range.add_equiv_symm (f : M ≃+ N) :
((map_range.add_equiv f).symm : (α →₀ _) ≃+ _) = map_range.add_equiv f.symm :=
add_equiv.ext $ λ x, rfl

end add_monoid_hom

end map_range

Expand Down Expand Up @@ -1192,6 +1277,7 @@ begin
(assume a' h', single_eq_of_ne $ assume eq, h $ eq ▸ set.mem_range_self _)
end

@[simp]
lemma map_domain_id : map_domain id v = v :=
sum_single _

Expand All @@ -1205,6 +1291,7 @@ begin
{ exact single_zero }
end

@[simp]
lemma map_domain_single {f : α → β} {a : α} {b : M} : map_domain f (single a b) = single (f a) b :=
sum_single_index single_zero

Expand All @@ -1218,13 +1305,29 @@ finset.sum_congr rfl $ λ _ H, by simp only [h _ H]
lemma map_domain_add {f : α → β} : map_domain f (v₁ + v₂) = map_domain f v₁ + map_domain f v₂ :=
sum_add_index (λ _, single_zero) (λ _ _ _, single_add)

/-- `finsupp.map_domain` is an `add_monoid_hom`. -/
@[simps]
def map_domain.add_monoid_hom (f : α → β) : (α →₀ M) →+ (β →₀ M) :=
{ to_fun := map_domain f,
map_zero' := map_domain_zero,
map_add' := λ _ _, map_domain_add}

@[simp]
lemma map_domain.add_monoid_hom_id : map_domain.add_monoid_hom id = add_monoid_hom.id (α →₀ M) :=
add_monoid_hom.ext $ λ _, map_domain_id

lemma map_domain.add_monoid_hom_comp (f : β → γ) (g : α → β) :
(map_domain.add_monoid_hom (f ∘ g) : (α →₀ M) →+ (γ →₀ M)) =
(map_domain.add_monoid_hom f).comp (map_domain.add_monoid_hom g) :=
add_monoid_hom.ext $ λ _, map_domain_comp

lemma map_domain_finset_sum {f : α → β} {s : finset ι} {v : ι → α →₀ M} :
map_domain f (∑ i in s, v i) = ∑ i in s, map_domain f (v i) :=
eq.symm $ sum_finset_sum_index (λ _, single_zero) (λ _ _ _, single_add)
(map_domain.add_monoid_hom f : (α →₀ M) →+ β →₀ M).map_sum _ _

lemma map_domain_sum [has_zero N] {f : α → β} {s : α →₀ N} {v : α → N → α →₀ M} :
map_domain f (s.sum v) = s.sum (λa b, map_domain f (v a b)) :=
eq.symm $ sum_finset_sum_index (λ _, single_zero) (λ _ _ _, single_add)
(map_domain.add_monoid_hom f : (α →₀ M) →+ β →₀ M).map_finsupp_sum _ _

lemma map_domain_support [decidable_eq β] {f : α → β} {s : α →₀ M} :
(s.map_domain f).support ⊆ s.support.image f :=
Expand Down Expand Up @@ -1277,6 +1380,18 @@ begin
rwa [map_domain_apply hf, map_domain_apply hf] at this,
end

lemma map_domain.add_monoid_hom_comp_map_range [add_comm_monoid N] (f : α → β) (g : M →+ N) :
(map_domain.add_monoid_hom f).comp (map_range.add_monoid_hom g) =
(map_range.add_monoid_hom g).comp (map_domain.add_monoid_hom f) :=
by { ext, simp }

/-- When `g` preserves addition, `map_range` and `map_domain` commute. -/
lemma map_domain_map_range [add_comm_monoid N] (f : α → β) (v : α →₀ M) (g : M → N)
(h0 : g 0 = 0) (hadd : ∀ x y, g (x + y) = g x + g y) :
map_domain f (map_range g h0 v) = map_range g h0 (map_domain f v) :=
let g' : M →+ N := { to_fun := g, map_zero' := h0, map_add' := hadd} in
add_monoid_hom.congr_fun (map_domain.add_monoid_hom_comp_map_range f g') v

end map_domain

/-! ### Declarations about `comap_domain` -/
Expand Down Expand Up @@ -1825,6 +1940,18 @@ map_range_single
(c : R) (a : α) (b : R) : c • finsupp.single a b = finsupp.single a (c * b) :=
smul_single _ _ _

lemma map_range_smul {_ : semiring R} [add_comm_monoid M] [semimodule R M]
[add_comm_monoid N] [semimodule R N]
{f : M → N} {hf : f 0 = 0} (c : R) (v : α →₀ M) (hsmul : ∀ x, f (c • x) = c • f x) :
map_range f hf (c • v) = c • map_range f hf v :=
begin
erw ←map_range_comp,
have : (f ∘ (•) c) = ((•) c ∘ f) := funext hsmul,
simp_rw this,
apply map_range_comp,
rw [function.comp_apply, smul_zero, hf],
end

lemma smul_single_one [semiring R] (a : α) (b : R) : b • single a 1 = single a b :=
by rw [smul_single, smul_eq_mul, mul_one]

Expand Down Expand Up @@ -1917,7 +2044,7 @@ protected def dom_congr [add_comm_monoid M] (e : α ≃ β) : (α →₀ M) ≃+
finsupp.dom_congr (equiv.refl α) = add_equiv.refl (α →₀ M) :=
add_equiv.ext $ λ _, map_domain_id

@[simp] lemma dom_congr_symm [add_comm_monoid M] (e : α ≃ β) :
@[simp] lemma dom_congr_symm [add_comm_monoid M] (e : α ≃ β) :
(finsupp.dom_congr e).symm = (finsupp.dom_congr e.symm : (β →₀ M) ≃+ (α →₀ M)):=
add_equiv.ext $ λ _, rfl

Expand Down
64 changes: 44 additions & 20 deletions src/linear_algebra/finsupp.lean
Expand Up @@ -58,9 +58,10 @@ open_locale classical big_operators

namespace finsupp

variables {α : Type*} {M : Type*} {N : Type*} {R : Type*} {S : Type*}
variables {α : Type*} {M : Type*} {N : Type*} {P : Type*} {R : Type*} {S : Type*}
variables [semiring R] [semiring S] [add_comm_monoid M] [semimodule R M]
variables [add_comm_monoid N] [semimodule R N]
variables [add_comm_monoid P] [semimodule R P]

/-- Interpret `finsupp.single a` as a linear map. -/
def lsingle (a : α) : M →ₗ[R] (α →₀ M) :=
Expand Down Expand Up @@ -521,11 +522,7 @@ by rw [finsupp.total_on, linear_map.range, linear_map.map_cod_restrict,

theorem total_comp (f : α' → α) :
(finsupp.total α' M R (v ∘ f)) = (finsupp.total α M R v).comp (lmap_domain R R f) :=
begin
ext l,
simp [total_apply],
rw sum_map_domain_index; simp [add_smul],
end
by { ext, simp [total_apply] }

lemma total_comap_domain
(f : α → α') (l : α' →₀ R) (hf : set.inj_on f (f ⁻¹' ↑l.support)) :
Expand Down Expand Up @@ -567,23 +564,50 @@ begin
exact finsupp.dom_lcongr e
end

/-- `finsupp.map_range` as a `linear_map`. -/
@[simps]
def map_range.linear_map (f : M →ₗ[R] N) : (α →₀ M) →ₗ[R] (α →₀ N) :=
{ to_fun := (map_range f f.map_zero : (α →₀ M) → (α →₀ N)),
map_smul' := λ c v, map_range_smul c v (f.map_smul c),
..map_range.add_monoid_hom f.to_add_monoid_hom }

@[simp]
lemma map_range.linear_map_id :
map_range.linear_map linear_map.id = (linear_map.id : (α →₀ M) →ₗ[R] _):=
linear_map.ext map_range_id

lemma map_range.linear_map_comp (f : N →ₗ[R] P) (f₂ : M →ₗ[R] N) :
(map_range.linear_map (f.comp f₂) : (α →₀ _) →ₗ[R] _) =
(map_range.linear_map f).comp (map_range.linear_map f₂) :=
linear_map.ext $ map_range_comp _ _ _ _ _

/-- `finsupp.map_range` as a `linear_equiv`. -/
@[simps apply]
def map_range.linear_equiv (e : M ≃ₗ[R] N) : (α →₀ M) ≃ₗ[R] (α →₀ N) :=
{ to_fun := map_range e e.map_zero,
inv_fun := map_range e.symm e.symm.map_zero,
..map_range.linear_map e.to_linear_map,
..map_range.add_equiv e.to_add_equiv}

@[simp]
lemma map_range.linear_equiv_refl :
map_range.linear_equiv (linear_equiv.refl R M) = linear_equiv.refl R (α →₀ M) :=
linear_equiv.ext map_range_id

lemma map_range.linear_equiv_trans (f : M ≃ₗ[R] N) (f₂ : N ≃ₗ[R] P) :
(map_range.linear_equiv (f.trans f₂) : linear_equiv R (α →₀ _) _) =
(map_range.linear_equiv f).trans (map_range.linear_equiv f₂) :=
linear_equiv.ext $ map_range_comp _ _ _ _ _

@[simp]
lemma map_range.linear_equiv_symm (f : M ≃ₗ[R] N) :
((map_range.linear_equiv f).symm : (α →₀ _) ≃ₗ[R] _) = map_range.linear_equiv f.symm :=
linear_equiv.ext $ λ x, rfl

/-- An equivalence of domain and a linear equivalence of codomain induce a linear equivalence of the
corresponding finitely supported functions. -/
def lcongr {ι κ : Sort*} (e₁ : ι ≃ κ) (e₂ : M ≃ₗ[R] N) : (ι →₀ M) ≃ₗ[R] (κ →₀ N) :=
(finsupp.dom_lcongr e₁).trans
{ to_fun := map_range e₂ e₂.map_zero,
inv_fun := map_range e₂.symm e₂.symm.map_zero,
left_inv := λ f, finsupp.induction f (by simp_rw map_range_zero) $ λ a b f ha hb ih,
by rw [map_range_add e₂.map_add, map_range_add e₂.symm.map_add,
map_range_single, map_range_single, e₂.symm_apply_apply, ih],
right_inv := λ f, finsupp.induction f (by simp_rw map_range_zero) $ λ a b f ha hb ih,
by rw [map_range_add e₂.symm.map_add, map_range_add e₂.map_add,
map_range_single, map_range_single, e₂.apply_symm_apply, ih],
map_add' := map_range_add e₂.map_add,
map_smul' := λ c f, finsupp.induction f
(by rw [smul_zero, map_range_zero, smul_zero]) $ λ a b f ha hb ih,
by rw [smul_add, smul_single, map_range_add e₂.map_add, map_range_single, e₂.map_smul, ih,
map_range_add e₂.map_add, smul_add, map_range_single, smul_single] }
(finsupp.dom_lcongr e₁).trans (map_range.linear_equiv e₂)

@[simp] theorem lcongr_single {ι κ : Sort*} (e₁ : ι ≃ κ) (e₂ : M ≃ₗ[R] N)
(i : ι) (m : M) : lcongr e₁ e₂ (finsupp.single i m) = finsupp.single (e₁ i) (e₂ m) :=
Expand Down

0 comments on commit 394719f

Please sign in to comment.