Skip to content

Commit

Permalink
feat(*): various lemmas from the sensitivity project (#1550)
Browse files Browse the repository at this point in the history
* feat(*): various lemmas from the sensitivity project

* fix proof broken by nonterminal simp

* Update src/linear_algebra/dual.lean

Co-Authored-By: Johan Commelin <johan@commelin.net>

* lint dual.lean

* remove decidable_mem_of_fintype instance

this leads to loops with `subtype.fintype` under the right decidable_eq assumptions

* dual_lc is invalid simp lemma

* fix namespace

* add extra lemma

* fix sum_const

* remove unnecessary dec_eq assumptions

* remove decidable_eq assumptions

* document dual.lean

* use classical locale

* remove some unnecessary includes

* remove an unused variable

* Update src/linear_algebra/dual.lean

* fixing a doc comment
  • Loading branch information
robertylewis authored and mergify[bot] committed Oct 21, 2019
1 parent 96ebf8c commit 39092ab
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 22 deletions.
18 changes: 16 additions & 2 deletions src/algebra/module.lean
Expand Up @@ -8,8 +8,8 @@ Modules over a ring.
## Implemetation notes
Throughout the `linear_map` section implicit `{}` brackets are often used instead of type class `[]` brackets.
This is done when the instances can be inferred because they are implicit arguments to the type `linear_map`.
Throughout the `linear_map` section implicit `{}` brackets are often used instead of type class `[]` brackets.
This is done when the instances can be inferred because they are implicit arguments to the type `linear_map`.
When they can be inferred from the type it is faster to use this method than to use type class inference
-/
Expand Down Expand Up @@ -420,3 +420,17 @@ def is_add_group_hom.to_linear_map [add_comm_group α] [add_comm_group β]
smul := λ i x, int.induction_on i (by rw [zero_smul, zero_smul, is_add_group_hom.map_zero f])
(λ i ih, by rw [add_smul, add_smul, is_add_hom.map_add f, ih, one_smul, one_smul])
(λ i ih, by rw [sub_smul, sub_smul, is_add_group_hom.map_sub f, ih, one_smul, one_smul]) }

lemma module.smul_eq_smul {R : Type*} [ring R] {β : Type*} [add_comm_group β] [module R β]
(n : ℕ) (b : β) : n • b = (n : R) • b :=
begin
induction n with n ih,
{ rw [nat.cast_zero, zero_smul, zero_smul] },
{ change (n + 1) • b = (n + 1 : R) • b,
rw [add_smul, add_smul, one_smul, ih, one_smul] }
end

lemma finset.sum_const' {α : Type*} (R : Type*) [ring R] {β : Type*}
[add_comm_group β] [module R β] {s : finset α} (b : β) :
finset.sum s (λ (a : α), b) = (finset.card s : R) • b :=
by rw [finset.sum_const, ← module.smul_eq_smul]; refl
4 changes: 4 additions & 0 deletions src/algebra/ring.lean
Expand Up @@ -56,6 +56,10 @@ theorem mul_two (n : α) : n * 2 = n + n :=
theorem bit0_eq_two_mul (n : α) : bit0 n = 2 * n :=
(two_mul _).symm

@[simp] lemma mul_ite {α} [semiring α] (P : Prop) [decidable P] (a : α) :
a * (if P then 1 else 0) = if P then a else 0 :=
by split_ifs; simp

variable (α)

/-- Either zero and one are nonequal in a semiring, or the semiring is the zero ring. -/
Expand Down
39 changes: 38 additions & 1 deletion src/data/set/finite.lean
Expand Up @@ -75,7 +75,11 @@ theorem finite_mem_finset (s : finset α) : finite {a | a ∈ s} :=
theorem finite.of_fintype [fintype α] (s : set α) : finite s :=
by classical; exact ⟨set_fintype s⟩

instance decidable_mem_of_fintype [decidable_eq α] (s : set α) [fintype s] (a) : decidable (a ∈ s) :=
/-- Membership of a subset of a finite type is decidable.
Using this as an instance leads to potential loops with `subtype.fintype` under certain decidability
assumptions, so it should only be declared a local instance. -/
def decidable_mem_of_fintype [decidable_eq α] (s : set α) [fintype s] (a) : decidable (a ∈ s) :=
decidable_of_iff _ mem_to_finset

instance fintype_empty : fintype (∅ : set α) :=
Expand Down Expand Up @@ -117,10 +121,16 @@ lemma card_image_of_injective (s : set α) [fintype s]
fintype.card (f '' s) = fintype.card s :=
card_image_of_inj_on $ λ _ _ _ _ h, H h

section

local attribute [instance] decidable_mem_of_fintype

instance fintype_insert [decidable_eq α] (a : α) (s : set α) [fintype s] : fintype (insert a s : set α) :=
if h : a ∈ s then by rwa [insert_eq, union_eq_self_of_subset_left (singleton_subset_iff.2 h)]
else fintype_insert' _ h

end

@[simp] theorem finite_insert (a : α) {s : set α} : finite s → finite (insert a s)
| ⟨h⟩ := ⟨@set.fintype_insert _ (classical.dec_eq α) _ _ h⟩

Expand Down Expand Up @@ -451,6 +461,19 @@ begin
{ exact ih c hcs hbc } }
end

section

local attribute [instance, priority 1] classical.prop_decidable

lemma to_finset_card {α : Type*} [fintype α] (H : set α) :
H.to_finset.card = fintype.card H :=
multiset.card_map subtype.val finset.univ.val

lemma to_finset_inter {α : Type*} [fintype α] (s t : set α) [decidable_eq α] :
(s ∩ t).to_finset = s.to_finset ∩ t.to_finset :=
by ext; simp

end
end set

namespace finset
Expand Down Expand Up @@ -497,3 +520,17 @@ calc
... = s.prod g : by rw image_preimage

end finset

lemma fintype.exists_max [fintype α] [nonempty α]
{β : Type*} [decidable_linear_order β] (f : α → β) :
∃ x₀ : α, ∀ x, f x ≤ f x₀ :=
begin
obtain ⟨y, hy⟩ : ∃ y, y ∈ (set.range f).to_finset,
{ haveI := classical.inhabited_of_nonempty ‹nonempty α›,
exact ⟨f (default α), set.mem_to_finset.mpr $ set.mem_range_self _⟩ },
rcases finset.max_of_mem hy with ⟨y₀, h⟩,
rcases set.mem_to_finset.1 (finset.mem_of_max h) with ⟨x₀, rfl⟩,
use x₀,
intro x,
apply finset.le_max_of_mem (set.mem_to_finset.mpr $ set.mem_range_self x) h
end
170 changes: 161 additions & 9 deletions src/linear_algebra/dual.lean
Expand Up @@ -2,24 +2,58 @@
Copyright (c) 2019 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin, Fabian Glöckle
Dual vector spaces, the spaces of linear functionals to the base field, including the dual basis
isomorphism and evaluation isomorphism in the finite-dimensional case.
-/
import linear_algebra.dimension

import linear_algebra.tensor_product
import linear_algebra.finite_dimensional
import tactic.apply_fun
noncomputable theory

/-!
# Dual vector spaces
The dual space of an R-module M is the R-module of linear maps `M → R`.
## Main definitions
* `dual R M` defines the dual space of M over R.
* Given a basis for a K-vector space `V`, `is_basis.to_dual` produces a map from `V` to `dual K V`.
* Given families of vectors `e` and `ε`, `dual_pair e ε` states that these families have the
characteristic properties of a basis and a dual.
## Main results
* `to_dual_equiv` : the dual space is linearly equivalent to the primal space.
* `dual_pair.is_basis` and `dual_pair.eq_dual`: if `e` and `ε` form a dual pair, `e` is a basis and
`ε` is its dual basis.
## Notation
We sometimes use `V'` as local notation for `dual K V`.
## Implementation details
Because of unresolved type class issues, the following local instance can be of use:
```
private def help_tcs : has_scalar K V := mul_action.to_has_scalar _ _
local attribute [instance] help_tcs
```
-/

namespace module
variables (R : Type*) (M : Type*)
variables [comm_ring R] [add_comm_group M] [module R M]

/-- The dual space of an R-module M is the R-module of linear maps `M → R`. -/
@[derive [add_comm_group, module R]] def dual := M →ₗ[R] R

namespace dual

instance : has_coe_to_fun (dual R M) := ⟨_, linear_map.to_fun⟩

/-- Maps a module M to the dual of the dual of M. See `vector_space.eval_range` and
`vector_space.eval_equiv`. -/
def eval : M →ₗ[R] (dual R (dual R M)) := linear_map.id.flip

lemma eval_apply (v : M) (a : dual R M) : (eval R M v) a = a v :=
Expand All @@ -39,11 +73,13 @@ open vector_space module module.dual submodule linear_map cardinal function

instance dual.vector_space : vector_space K (dual K V) := { ..module.dual.inst K V }

variables [decidable_eq ι]
variables [de : decidable_eq ι]
variables {B : ι → V} (h : is_basis K B)

include h
include de h

/-- The linear map from a vector space equipped with basis to its dual vector space,
taking basis elements to corresponding dual basis elements. -/
def to_dual : V →ₗ[K] module.dual K V :=
h.constr $ λ v, h.constr $ λ w, if w = v then 1 else 0

Expand All @@ -53,7 +89,8 @@ lemma to_dual_apply (i j : ι) :

def to_dual_flip (v : V) : (V →ₗ[K] K) := (linear_map.flip h.to_dual).to_fun v

omit h
omit de h
/-- Evaluation of finitely supported functions at a fixed point `i`, as a `K`-linear map. -/
def eval_finsupp_at (i : ι) : (ι →₀ K) →ₗ[K] K :=
{ to_fun := λ f, f i,
add := by intros; rw finsupp.add_apply,
Expand All @@ -66,6 +103,8 @@ def coord_fun (i : ι) : (V →ₗ[K] K) := (eval_finsupp_at i).comp h.repr

lemma coord_fun_eq_repr (v : V) (i : ι) : h.coord_fun i v = h.repr v i := rfl

include de

lemma to_dual_swap_eq_to_dual (v w : V) : h.to_dual_flip v w = h.to_dual w v := rfl

lemma to_dual_eq_repr (v : V) (i : ι) : (h.to_dual v) (B i) = h.repr v i :=
Expand Down Expand Up @@ -100,7 +139,6 @@ begin
intro f,
rw linear_map.mem_range,
let lin_comb : ι →₀ K := finsupp.on_finset fin.elems (λ i, f.to_fun (B i)) _,
--let emb := embedding.subtype B,
{ use finsupp.total ι V K B lin_comb,
apply h.ext,
{ intros i,
Expand All @@ -112,6 +150,7 @@ begin
apply fin.complete }
end

/-- Maps a basis for `V` to a basis for the dual space. -/
def dual_basis : ι → dual K V := λ i, h.to_dual (B i)

theorem dual_lin_independent : linear_independent K h.dual_basis :=
Expand All @@ -121,13 +160,14 @@ begin
exact disjoint_bot_right
end

/-- A vector space is linearly equivalent to its dual space. -/
def to_dual_equiv [fintype ι] : V ≃ₗ[K] (dual K V) :=
linear_equiv.of_bijective h.to_dual h.to_dual_ker h.to_dual_range

theorem dual_basis_is_basis [fintype ι] : is_basis K h.dual_basis :=
h.to_dual_equiv.is_basis h

@[simp] lemma to_dual_to_dual [decidable_eq (dual K (dual K V))] [fintype ι] :
@[simp] lemma to_dual_to_dual [fintype ι] :
(h.dual_basis_is_basis.to_dual).comp h.to_dual = eval K V :=
begin
apply @is_basis.ext _ _ _ _ _ _ _ _ _ _ _ _ h,
Expand Down Expand Up @@ -202,7 +242,119 @@ begin
apply_instance
end

/-- A vector space is linearly equivalent to the dual of its dual space. -/
def eval_equiv (h : dim K V < omega) : V ≃ₗ[K] dual K (dual K V) :=
linear_equiv.of_bijective (eval K V) eval_ker (eval_range h)

end vector_space

section dual_pair

open vector_space module module.dual linear_map function

universes u v w
variables {K : Type u} {V : Type v} {ι : Type w} [decidable_eq ι]
variables [discrete_field K] [add_comm_group V] [vector_space K V]

local notation `V'` := dual K V

/-- `e` and `ε` have characteristic properties of a basis and its dual -/
structure dual_pair (e : ι → V) (ε : ι → V') :=
(eval : ∀ i j : ι, ε i (e j) = if i = j then 1 else 0)
(total : ∀ {v : V}, (∀ i, ε i v = 0) → v = 0)
[finite : ∀ v : V, fintype {i | ε i v ≠ 0}]

end dual_pair

namespace dual_pair

open vector_space module module.dual linear_map function

universes u v w
variables {K : Type u} {V : Type v} {ι : Type w} [dι : decidable_eq ι]
variables [discrete_field K] [add_comm_group V] [vector_space K V]
variables {e : ι → V} {ε : ι → dual K V} (h : dual_pair e ε)

include h

/-- The coefficients of `v` on the basis `e` -/
def coeffs (v : V) : ι →₀ K :=
{ to_fun := λ i, ε i v,
support := by { haveI := h.finite v, exact {i : ι | ε i v ≠ 0}.to_finset },
mem_support_to_fun := by {intro i, rw set.mem_to_finset, exact iff.rfl } }


@[simp] lemma coeffs_apply (v : V) (i : ι) : h.coeffs v i = ε i v := rfl

omit h
private def help_tcs : has_scalar K V := mul_action.to_has_scalar _ _

local attribute [instance] help_tcs

/-- linear combinations of elements of `e`.
This is a convenient abbreviation for `finsupp.total _ V K e l` -/
def lc (e : ι → V) (l : ι →₀ K) : V := l.sum (λ (i : ι) (a : K), a • (e i))

include h

lemma dual_lc (l : ι →₀ K) (i : ι) : ε i (dual_pair.lc e l) = l i :=
begin
erw linear_map.map_sum,
simp only [h.eval, map_smul, smul_eq_mul],
rw finset.sum_eq_single i,
{ simp },
{ intros q q_in q_ne,
simp [q_ne.symm] },
{ intro p_not_in,
simp [finsupp.not_mem_support_iff.1 p_not_in] },
end

@[simp]
lemma coeffs_lc (l : ι →₀ K) : h.coeffs (dual_pair.lc e l) = l :=
by { ext i, rw [h.coeffs_apply, h.dual_lc] }

/-- For any v : V n, \sum_{p ∈ Q n} (ε p v) • e p = v -/
lemma decomposition (v : V) : dual_pair.lc e (h.coeffs v) = v :=
begin
refine eq_of_sub_eq_zero (h.total _),
intros i,
simp [-sub_eq_add_neg, linear_map.map_sub, h.dual_lc, sub_eq_zero_iff_eq]
end

lemma mem_of_mem_span {H : set ι} {x : V} (hmem : x ∈ submodule.span K (e '' H)) :
∀ i : ι, ε i x ≠ 0 → i ∈ H :=
begin
intros i hi,
rcases (finsupp.mem_span_iff_total _).mp hmem with ⟨l, supp_l, sum_l⟩,
change dual_pair.lc e l = x at sum_l,
rw finsupp.mem_supported' at supp_l,
apply classical.by_contradiction,
intro i_not,
apply hi,
rw ← sum_l,
simpa [h.dual_lc] using supp_l i i_not
end

lemma is_basis : is_basis K e :=
begin
split,
{ rw linear_independent_iff,
intros l H,
change dual_pair.lc e l = 0 at H,
ext i,
apply_fun ε i at H,
simpa [h.dual_lc] using H },
{ rw submodule.eq_top_iff',
intro v,
rw [← set.image_univ, finsupp.mem_span_iff_total],
exact ⟨h.coeffs v, by simp, h.decomposition v⟩ },
end

lemma eq_dual : ε = is_basis.dual_basis h.is_basis :=
begin
funext i,
refine h.is_basis.ext (λ _, _),
erw [is_basis.to_dual_apply, h.eval]
end

end dual_pair
18 changes: 18 additions & 0 deletions src/linear_algebra/finite_dimensional.lean
Expand Up @@ -104,6 +104,24 @@ begin
rw [this, map_top (submodule.subtype S), range_subtype],
end

section

variables {ι : Type w} [fintype ι] [decidable_eq V]
variables {b : ι → V} (h : is_basis K b)
include h

lemma fg_of_finite_basis : submodule.fg (⊤ : submodule K V) :=
⟨ finset.univ.image b, by {convert h.2, simp} ⟩

def finite_dimensional_of_finite_basis : finite_dimensional K V :=
finite_dimensional.of_fg $ fg_of_finite_basis h

lemma dim_eq_card : dim K V = fintype.card ι :=
by rw [←h.mk_range_eq_dim, cardinal.fintype_card,
set.card_range_of_injective (h.injective zero_ne_one)]

end

end finite_dimensional

namespace linear_map
Expand Down

0 comments on commit 39092ab

Please sign in to comment.