Skip to content

Commit

Permalink
Merge branch 'master' into eric-wieser/tensor_base_change
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-wieser authored Oct 25, 2023
2 parents a7708f1 + 0947a6d commit 8b59e00
Show file tree
Hide file tree
Showing 5 changed files with 364 additions and 64 deletions.
105 changes: 68 additions & 37 deletions src/for_mathlib/linear_algebra/quadratic_form/isometric_map.lean
Original file line number Diff line number Diff line change
@@ -1,94 +1,125 @@
import linear_algebra.quadratic_form.isometry

/-! # Isometric linear maps
/-! # Isometric (semi)linear maps
Note that `quadratic_form.isometry` is already taken for isometric equivalences.
-/
set_option old_structure_cmd true

variables {ι R M M₁ M₂ M₃ M₄ : Type*}
variables {ι R R₁ R₂ R₃ R₄ M₁ M₂ M₃ M₄ : Type*}

namespace quadratic_form

variables [semiring R]
variables [add_comm_monoid M]
section semilinear

variables [semiring R₁] [semiring R₂] [semiring R₃] [semiring R₄]
variables [add_comm_monoid M₁] [add_comm_monoid M₂] [add_comm_monoid M₃] [add_comm_monoid M₄]
variables [module R M] [module R M₁] [module R M₂] [module R M₃] [module R M₄]
variables [module R₁ M₁] [module R M₂] [module R M₃] [module R M₄]

/-- An isometry between two quadratic spaces `M₁, Q₁` and `M₂, Q₂` over a ring `R`,
is a linear equivalence between `M₁` and `M₂` that commutes with the quadratic forms. -/
@[nolint has_nonempty_instance] structure isometric_map
(Q₁ : quadratic_form R M₁) (Q₂ : quadratic_form R M₂) extends M₁ →ₗ[R] M₂ :=
(map_app' : ∀ m, Q₂ (to_fun m) = Q₁ m)
@[nolint has_nonempty_instance] structure isometric_map (σ : R₁ →+* R₂)
(Q₁ : quadratic_form R₁ M₁) (Q₂ : quadratic_form R₂ M₂) extends M₁ →ₛₗ[σ] M₂ :=
(map_app' : ∀ m, Q₂ (to_fun m) = σ (Q₁ m))


notation Q₁ ` →qₛₗ[`:25 σ:25 `] `:0 Q₂:0 := isometric_map σ Q₁ Q₂
notation Q₁ ` →qᵢ `:25 Q₂:0 := isometric_map (ring_hom.id _) Q₁ Q₂

namespace isometric_map

variables {Q₁ : quadratic_form R M₁} {Q₂ : quadratic_form R M₂}
variables {Q₃ : quadratic_form R M₃} {Q₄ : quadratic_form R M₄}

instance : semilinear_map_class (Q₁.isometric_map Q₂) (ring_hom.id R) M₁ M₂ :=
variables {σ₁₂ : R₁ →+* R₂} {σ₂₃ : R₂ →+* R₃} {σ₃₄ : R₃ →+* R₄}
variables {σ₁₃ : R₁ →+* R₃} {σ₂₄ : R₂ →+* R₄} {σ₁₄ : R₁ →+* R₄}
variables {Q₁ : quadratic_form R₁ M₁} {Q₂ : quadratic_form R₂ M₂}
variables {Q₃ : quadratic_form R₃ M₃} {Q₄ : quadratic_form R₄ M₄}

instance : semilinear_map_class (Q₁ →qₛₗ[σ₁₂] Q₂) σ₁₂ M₁ M₂ :=
{ coe := λ f, f.to_linear_map,
coe_injective' := λ f g h, by cases f; cases g; congr',
map_add := λ f, f.to_linear_map.map_add,
map_smulₛₗ := λ f, f.to_linear_map.map_smul }
map_smulₛₗ := λ f, f.to_linear_map.map_smulₛₗ }

lemma to_linear_map_injective :
function.injective (isometric_map.to_linear_map : (Q₁.isometric_map Q₂) → (M₁ →ₗ[R] M₂)) :=
function.injective (isometric_map.to_linear_map : (Q₁ →qₛₗ[σ₁₂] Q₂) → (M₁ →ₛₗ[σ₁₂] M₂)) :=
λ f g h, fun_like.coe_injective (congr_arg fun_like.coe h : _)

@[ext] lemma ext ⦃f g : Q₁.isometric_map Q₂⦄ (h : ∀ x, f x = g x) : f = g := fun_like.ext _ _ h
@[ext] lemma ext ⦃f g : Q₁ →qₛₗ[σ₁₂] Q₂⦄ (h : ∀ x, f x = g x) : f = g := fun_like.ext _ _ h

/-- See Note [custom simps projection]. -/
protected def simps.apply (f : Q₁.isometric_map Q₂) : M₁ → M₂ := f
protected def simps.apply (f : Q₁ →qₛₗ[σ₁₂] Q₂) : M₁ → M₂ := f

initialize_simps_projections isometric_map (to_fun → apply)

@[simp] lemma map_app (f : Q₁.isometric_map Q₂) (m : M₁) : Q₂ (f m) = Q₁ m := f.map_app' m
@[simp] lemma map_appₛₗ (f : Q₁ →qₛₗ[σ₁₂] Q₂) (m : M₁) : Q₂ (f m) = σ₁₂ (Q₁ m) := f.map_app' m

@[simp] lemma coe_to_linear_map (f : Q₁.isometric_map Q₂) : ⇑f.to_linear_map = f := rfl
@[simp] lemma coe_to_linear_map (f : Q₁ →qₛₗ[σ₁₂] Q₂) : ⇑f.to_linear_map = f := rfl

/-- The identity isometry from a quadratic form to itself. -/
@[simps]
def id (Q : quadratic_form R M) : Q.isometric_map Q :=
def id (Q : quadratic_form R₁ M₁) : Q →qᵢ Q :=
{ map_app' := λ m, rfl,
.. linear_map.id }

/-- The composition of two isometries between quadratic forms. -/
@[simps]
def comp (g : Q₂.isometric_map Q₃) (f : Q₁.isometric_map Q₂) : Q₁.isometric_map Q₃ :=
def comp [ring_hom_comp_triple σ₁₂ σ₂₃ σ₁₃] (g : Q₂ →qₛₗ[σ₂₃] Q₃) (f : Q₁ →qₛₗ[σ₁₂] Q₂) : Q₁ →qₛₗ[σ₁₃] Q₃ :=
{ to_fun := λ x, g (f x),
map_app' := by { intro m, rw [← f.map_app, ← g.map_app] },
.. (g.to_linear_map : M₂ →ₗ[R] M₃).comp (f.to_linear_map : M₁ →ₗ[R] M₂) }
map_app' := λ m,
by rw [←@ring_hom_comp_triple.comp_apply _ _ _ _ _ _ σ₁₂ σ₂₃ σ₁₃, ← f.map_appₛₗ, ← g.map_appₛₗ],
.. (g.to_linear_map : M₂ →ₛₗ[σ₂₃] M₃).comp (f.to_linear_map : M₁ →ₛₗ[σ₁₂] M₂) }

@[simp] lemma to_linear_map_comp (g : Q₂.isometric_map Q₃) (f : Q₁.isometric_map Q₂) :
@[simp] lemma to_linear_map_comp [ring_hom_comp_triple σ₁₂ σ₂₃ σ₁₃] (g : Q₂ →qₛₗ[σ₂₃] Q₃) (f : Q₁ →qₛₗ[σ₁₂] Q₂) :
(g.comp f).to_linear_map = g.to_linear_map.comp f.to_linear_map := rfl

@[simp] lemma id_comp (f : Q₁.isometric_map Q₂) : (id Q₂).comp f = f := ext $ λ _, rfl
@[simp] lemma comp_id (f : Q₁.isometric_map Q₂) : f.comp (id Q₁) = f := ext $ λ _, rfl
lemma comp_assoc (h : Q₃.isometric_map Q₄) (g : Q₂.isometric_map Q₃) (f : Q₁.isometric_map Q₂) :
@[simp] lemma id_comp (f : Q₁ →qₛₗ[σ₁₂] Q₂) : (id Q₂).comp f = f := ext $ λ _, rfl
@[simp] lemma comp_id (f : Q₁ →qₛₗ[σ₁₂] Q₂) : f.comp (id Q₁) = f := ext $ λ _, rfl
lemma comp_assoc
[ring_hom_comp_triple σ₁₂ σ₂₃ σ₁₃] [ring_hom_comp_triple σ₂₃ σ₃₄ σ₂₄]
[ring_hom_comp_triple σ₁₂ σ₂₄ σ₁₄] [ring_hom_comp_triple σ₁₃ σ₃₄ σ₁₄]
(h : Q₃ →qₛₗ[σ₃₄] Q₄) (g : Q₂ →qₛₗ[σ₂₃] Q₃) (f : Q₁ →qₛₗ[σ₁₂] Q₂) :
(h.comp g).comp f = h.comp (g.comp f) := ext $ λ _, rfl

/-- Isometries are isometric maps -/
@[simps]
def _root_.quadratic_form.isometry.to_isometric_map (g : Q₁.isometry Q₂) :
Q₁.isometric_map Q₂ := { ..g }

/-- There is a zero map from any module with the zero form. -/
instance : has_zero ((0 : quadratic_form R M₁).isometric_map Q₂) :=
instance : has_zero ((0 : quadratic_form R M₁) →qₛₗ[σ₁₂] Q₂) :=
{ zero :=
{ map_app' := λ m, map_zero _,
..(0 : M₁ →ₗ[R] M₂) } }
{ map_app' := λ m, (map_zero _).trans (_root_.map_zero _).symm,
..(0 : M₁ →ₛₗ[σ₁₂] M₂) } }

/-- There is a zero map from the trivial module. -/
instance [subsingleton M₁] : has_zero (Q₁.isometric_map Q₂) :=
instance has_zero_of_subsingleton [subsingleton M₁] : has_zero (Q₁ →qₛₗ[σ₁₂] Q₂) :=
{ zero :=
{ map_app' := λ m, subsingleton.elim 0 m ▸ (map_zero _).trans (map_zero _).symm,
..(0 : M₁ →ₗ[R] M₂) } }
{ map_app' := λ m, subsingleton.elim 0 m ▸ (map_zero _).trans $
(_root_.map_zero σ₁₂).symm.trans $ σ₁₂.congr_arg (map_zero _).symm,
..(0 : M₁ →ₛₗ[σ₁₂] M₂) } }

/-- Maps into the zero module are trivial -/
instance [subsingleton M₂] : subsingleton (Q₁.isometric_map Q₂) :=
instance [subsingleton M₂] : subsingleton (Q₁ →qₛₗ[σ₁₂] Q₂) :=
⟨λ f g, ext $ λ _, subsingleton.elim _ _⟩

end isometric_map

end semilinear

section linear

namespace isometric_map

variables [semiring R]
variables [add_comm_monoid M₁] [add_comm_monoid M₂] [add_comm_monoid M₃] [add_comm_monoid M₄]
variables [module R M₁] [module R M₂] [module R M₃] [module R M₄]

variables {Q₁ : quadratic_form R M₁} {Q₂ : quadratic_form R M₂}

/-- Isometries are isometric maps -/
@[simps]
def _root_.quadratic_form.isometry.to_isometric_map (g : Q₁.isometry Q₂) :
Q₁ →qᵢ Q₂ := { ..g }

@[simp] lemma map_app (f : Q₁ →qᵢ Q₂) (m : M₁) : Q₂ (f m) = Q₁ m := f.map_app' m

end isometric_map

end linear

end quadratic_form
22 changes: 12 additions & 10 deletions src/for_mathlib/linear_algebra/quadratic_form/prod.lean
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ variables [fintype ι] (QM₁ : quadratic_form R M₁) (QM₂ : quadratic_form R
variables (QN₁ : quadratic_form R N₁) (QN₂ : quadratic_form R N₂)

/-- `linear_map.inl` as an `isometric_map`. -/
@[simps] def inl [decidable_eq ι] (i : ι) : QM₁.isometric_map (QM₁.prod QM₂) :=
@[simps] def inl [decidable_eq ι] (i : ι) : QM₁ →qᵢ QM₁.prod QM₂ :=
{ map_app' := λ x, by simp,
.. linear_map.inl R M₁ M₂ }

/-- `linear_map.inl` as an `isometric_map`. -/
@[simps] def inr [decidable_eq ι] (i : ι) : QM₂.isometric_map (QM₁.prod QM₂) :=
@[simps] def inr [decidable_eq ι] (i : ι) : QM₂ →qᵢ QM₁.prod QM₂ :=
{ map_app' := λ x, by simp,
.. linear_map.inr R M₁ M₂ }

Expand All @@ -36,16 +36,16 @@ variables {QM₁ QM₂ QN₁ QN₂}
/-- `pi.prod` of two isometric maps. -/
@[simps]
def prod {fQM₁ gQM₁ : quadratic_form R M₁}
(f : fQM₁.isometric_map QN₁) (g : gQM₁.isometric_map QN₂) :
(fQM₁ + gQM₁).isometric_map (QN₁.prod QN₂) :=
(f : fQM₁ →qᵢ QN₁) (g : gQM₁ →qᵢ QN₂) :
(fQM₁ + gQM₁) →qᵢ QN₁.prod QN₂ :=
{ to_fun := pi.prod f g,
map_app' := λ x, congr_arg2 (+) (f.map_app _) (g.map_app _),
.. linear_map.prod f.to_linear_map g.to_linear_map }

/-- `prod.map` of two isometric maps. -/
@[simps]
def prod_map (f : QM₁.isometric_map QN₁) (g : QM₂.isometric_map QN₂) :
(QM₁.prod QM₂).isometric_map (QN₁.prod QN₂) :=
def prod_map (f : QM₁ →qᵢ QN₁) (g : QM₂ →qᵢ QN₂) :
QM₁.prod QM₂ →qᵢ QN₁.prod QN₂ :=
{ map_app' := λ x, congr_arg2 (+) (f.map_app _) (g.map_app _),
.. linear_map.prod_map f.to_linear_map g.to_linear_map }

Expand All @@ -56,20 +56,22 @@ variables [fintype ι] (QM₁ : ι → quadratic_form R M₁) (QMᵢ : Π i, qua

/-- `linear_map.single` as an `isometric_map`. -/
@[simps]
def single [decidable_eq ι] (i : ι) : (QMᵢ i).isometric_map (quadratic_form.pi QMᵢ) :=
def single [decidable_eq ι] (i : ι) : QMᵢ i →qᵢ quadratic_form.pi QMᵢ :=
{ to_fun := pi.single i,
map_app' := λ x, (pi_apply QMᵢ _).trans $ begin
rw ring_hom.id_apply,
refine (fintype.sum_eq_single i $ λ j hij, _).trans _,
{ rw [pi.single_eq_of_ne hij, map_zero] },
{ rw [pi.single_eq_same] }
end,
.. (linear_map.single i : Mᵢ i →ₗ[R] (Π i, Mᵢ i))}

/-- `linear_map.pi` for `isometric_map`. -/
def pi (f : Π i, (QM₁ i).isometric_map (QMᵢ i)) :
(∑ i, QM₁ i).isometric_map (quadratic_form.pi QMᵢ) :=
def pi (f : Π i, QM₁ i →qᵢ QMᵢ i) :
(∑ i, QM₁ i) →qᵢ quadratic_form.pi QMᵢ :=
{ to_fun := λ c i, f i c,
map_app' := λ c, (pi_apply QMᵢ _).trans $ by simp_rw [λ i, (f i).map_app, sum_apply],
map_app' := λ c, (pi_apply QMᵢ _).trans $
by simp_rw [λ i, (f i).map_app, sum_apply, ring_hom.id_apply],
.. linear_map.pi (λ i, (f i).to_linear_map) }

end pi
Expand Down
9 changes: 9 additions & 0 deletions src/geometric_algebra/from_mathlib/basic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ begin
simp_rw [←algebra.smul_def, two_smul],
rw [h x x, quadratic_form.polar_bilin_apply, quadratic_form.polar_self, two_mul, map_add], },
end

instance [ring A] [algebra R A] :
has_zero (clifford_hom (0 : quadratic_form R M) A) :=
{ zero := ⟨0, λ m, by simp⟩ }

instance has_zero_of_subsingleton [ring A] [algebra R A] [subsingleton A] :
has_zero (clifford_hom Q A) :=
{ zero := ⟨0, λ m, subsingleton.elim _ _⟩ }

variables {Q}

/-- TODO: work out what the necessary conditions are here, then make this an instance -/
Expand Down
54 changes: 47 additions & 7 deletions src/geometric_algebra/from_mathlib/category_theory.lean
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import algebra.category.Algebra.basic
import linear_algebra.clifford_algebra.basic
import linear_algebra.exterior_algebra.basic
import geometric_algebra.from_mathlib.basic
import for_mathlib.linear_algebra.quadratic_form.isometric_map

Expand All @@ -9,7 +10,7 @@ import for_mathlib.linear_algebra.quadratic_form.isometric_map
* `QuadraticModule R`: the category of quadratic modules
* `CliffordAlgebra`: the functor from quadratic modules to algebras
* `clifford_algebra.is_initial`: the clifford algebra is initial in the category of pairs
* `Cliff.is_initial_clifford_algebra`: the clifford algebra is initial in the category of pairs
`(A, clifford_hom Q A)`.
-/
Expand All @@ -18,6 +19,16 @@ open category_theory
open quadratic_form
open clifford_algebra

instance _root_.alg_hom.has_zero_of_subsingleton (R A B : Type*)
[comm_semiring R] [semiring A] [algebra R A] [semiring B] [algebra R B] [subsingleton A] :
has_zero (B →ₐ[R] A) :=
{ zero :=
{ to_fun := 0,
map_one' := subsingleton.elim _ _,
map_mul' := λ _ _, subsingleton.elim _ _,
commutes' := λ _, subsingleton.elim _ _,
..(0 : B →+ A) } }

universes v u w

set_option old_structure_cmd true
Expand All @@ -41,7 +52,7 @@ instance (V : QuadraticModule.{v} R) : module R V := V.is_module
def form (V : QuadraticModule.{v} R) : quadratic_form R V := V.form'

instance category : category (QuadraticModule.{v} R) :=
{ hom := λ M N, M.form.isometric_map N.form,
{ hom := λ M N, M.form →qᵢ N.form,
id := λ M, isometric_map.id M.form,
comp := λ A B C f g, g.comp f,
id_comp' := λ X Y, isometric_map.id_comp,
Expand All @@ -66,7 +77,10 @@ instance (M N : QuadraticModule R) : linear_map_class (M ⟶ N) R M N :=

end QuadraticModule

/-- The "clifford algebra" functor, sending a quadratic R-module V to the clifford algebra on `V`. -/
/-- The "clifford algebra" functor, sending a quadratic `R`-module `V` to the clifford algebra on
`V`.
This is `clifford_algebra.map` through the lens of category theory. -/
@[simps]
def CliffordAlgebra : QuadraticModule.{u} R ⥤ Algebra.{u} R :=
{ obj := λ M,
Expand All @@ -75,6 +89,17 @@ def CliffordAlgebra : QuadraticModule.{u} R ⥤ Algebra.{u} R :=
map_id' := λ X, clifford_algebra.map_id _,
map_comp' := λ M N P f g, (clifford_algebra.map_comp_map _ _ _ _ _ _ _).symm }

/-- The "exterior algebra" functor, sending an `R`-module `V` to the exterior algebra on `V`.
In the language of geometric algebra, `(ExteriorAlgebra R).map f` is the outermorphism. -/
@[simps]
def ExteriorAlgebra : Module.{u} R ⥤ Algebra.{u} R :=
{ obj := λ M,
{ carrier := exterior_algebra R M },
map := λ M N f, clifford_algebra.map _ _ f (by simp),
map_id' := λ X, clifford_algebra.map_id _,
map_comp' := λ M N P f g, (clifford_algebra.map_comp_map _ _ _ _ _ _ _).symm }

variables {M : Type w} [add_comm_group M] [module R M] (Q : quadratic_form R M)

/--
Expand All @@ -90,7 +115,10 @@ namespace Cliff

/-- Convert a `clifford_hom Q A` to an element of `Cliff Q`. -/
def of {A : Type v} [ring A] [algebra R A] (f : clifford_hom Q A) : Cliff.{v} Q :=
{ alg := Algebra.of R A, hom := f }
{ alg := Algebra.of R A, hom := f }

/-- `clifford_algebra Q` as an element of `Cliff Q` -/
@[reducible] protected def clifford_algebra : Cliff Q := Cliff.of Q ⟨ι Q, ι_sq_scalar Q⟩

instance : category (Cliff Q) :=
{ hom := λ f g, {h : f.alg ⟶ g.alg // (alg_hom.to_linear_map h).comp f.hom.val = g.hom.val },
Expand All @@ -111,15 +139,27 @@ instance has_forget_to_Algebra : has_forget₂ (Cliff Q) (Algebra R) :=
{ obj := λ x, x.alg,
map := λ x y f, f.val } }

instance (Y : Cliff Q) : unique (Cliff.of Q ⟨ι Q, ι_sq_scalar Q⟩ ⟶ Y) :=
instance unique_from (Y : Cliff Q) : unique (Cliff.clifford_algebra Q ⟶ Y) :=
{ default := ⟨clifford_algebra.lift Q Y.hom, let ⟨A, ι, hι⟩ := Y in ι_comp_lift ι hι⟩,
uniq := λ f, subtype.ext begin
obtain ⟨A, ι, hι⟩ := Y,
exact (clifford_algebra.lift_unique _ hι f.val).mp f.prop,
end }

end Cliff
instance unique_to (X : Cliff Q) {A : Type v} [ring A] [algebra R A] [subsingleton A]
(f : clifford_hom Q A):
unique (X ⟶ Cliff.of Q f) :=
{ default := ⟨(0 : X.alg →ₐ[R] A), linear_map.ext $ λ x, @subsingleton.elim A _ _ _⟩,
uniq := λ f, subtype.ext $ alg_hom.ext (λ x, @subsingleton.elim A _ _ _) }

/-- The clifford algebra is the initial object in `Cliff`. -/
def clifford_algebra.is_initial : limits.is_initial (Cliff.of Q ⟨ι Q, ι_sq_scalar Q⟩) :=
def is_initial_clifford_algebra : limits.is_initial (Cliff.clifford_algebra Q) :=
limits.is_initial.of_unique _

/-- A trivial algebra is a terminal object in `Cliff`. -/
def is_terminal_of_subsingleton
{A : Type v} [ring A] [algebra R A] [subsingleton A] :
limits.is_terminal (Cliff.of Q (0 : clifford_hom _ A)) :=
limits.is_terminal.of_unique _

end Cliff
Loading

0 comments on commit 8b59e00

Please sign in to comment.