10. Aljabar Linear

10.1. Ruang vektor dan pemetaan linear

10.1.1. Ruang vektor

Kita akan langsung memulai dengan aljabar linear abstrak dalam konteks ruang vektor atas sembarang medan. Namun, Anda dapat menemukan informasi tentang matriks dalam Bagian 10.4.1, yang secara logis tidak bergantung pada teori abstrak ini. Sebenarnya, Mathlib menangani versi aljabar linear yang lebih umum dan melibatkan istilah modul, tetapi untuk sementara kita akan berpura-pura bahwa hal itu hanyalah kebiasaan ejaan yang nyentrik.

Cara menyatakan “misalkan \(K\) suatu medan dan \(V\) ruang vektor atas \(K\)” (serta menjadikannya argumen implisit bagi hasil-hasil berikutnya) adalah:

variable {K : Type*} [Field K] {V : Type*} [AddCommGroup V] [Module K V]

Dalam Bab 8, kita telah menjelaskan mengapa diperlukan dua kelas tipe terpisah, [AddCommGroup V] [Module K V]. Secara ringkas, alasannya sebagai berikut. Secara matematis, kita ingin mengatakan bahwa adanya struktur ruang vektor atas \(K\) mengakibatkan adanya struktur grup aditif komutatif. Kita dapat memberi tahu Lean tentang hal ini. Akan tetapi, setiap kali Lean perlu menemukan struktur grup semacam itu pada tipe \(V\), Lean kemudian harus mencari struktur ruang vektor dengan medan \(K\) yang sama sekali tidak ditentukan dan tidak dapat disimpulkan dari \(V\). Hal itu akan sangat merugikan sistem sintesis kelas tipe.

Perkalian vektor v dengan skalar a dinotasikan sebagai a v. Contoh berikut mencantumkan beberapa aturan aljabar mengenai interaksi operasi ini dengan penjumlahan. Tentu saja, simp atau apply? dapat menemukan bukti-bukti tersebut. Terdapat pula taktik module yang menyelesaikan sasaran yang mengikuti aksioma ruang vektor dan medan, sebagaimana taktik ring digunakan dalam gelanggang komutatif atau taktik group digunakan dalam grup. Namun, tetap berguna untuk mengingat bahwa perkalian skalar disingkat smul dalam nama lemma.

example (a : K) (u v : V) : a  (u + v) = a  u + a  v :=
  smul_add a u v

example (a b : K) (u : V) : (a + b)  u = a  u + b  u :=
  add_smul a b u

example (a b : K) (u : V) : a  b  u = b  a  u :=
  smul_comm a b u

Sebagai catatan singkat bagi pembaca yang lebih mahir, sesuai petunjuk terminologinya, aljabar linear Mathlib juga mencakup modul atas gelanggang (yang tidak harus komutatif). Bahkan, cakupannya meliputi semimodul atas semigelanggang. Jika Anda merasa tidak memerlukan tingkat keumuman ini, renungkan contoh berikut, yang dengan apik merangkum banyak aturan aljabar mengenai aksi ideal pada submodul:

example {R M : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] :
    Module (Ideal R) (Submodule R M) :=
  inferInstance

Untuk menyatakan bahwa M merupakan modul atas gelanggang R, kita menulis:

section
variable {R : Type*} [Ring R] {M : Type*} [AddCommGroup M] [Module R M]
end

Jika dibandingkan dengan deklarasi ruang vektor, tampak dua perbedaan. Selain mengganti nama variabel, satu-satunya perubahan ialah mengganti hipotesis Field K dengan hipotesis Ring R.

Untuk menyatakan bahwa M merupakan semimodul atas semigelanggang R, kita mengganti hipotesis Ring R dengan hipotesis Semiring R dan juga mengganti AddCommGroup M dengan AddCommMonoid M. Perubahan ini mencerminkan fakta bahwa semimodul tidak memiliki negasi:

section
variable {R : Type*} [Semiring R] {M : Type*} [AddCommMonoid M] [Module R M]
end

Lean tidak dapat secara otomatis menyimpulkan bahwa M memiliki negasi jika R memilikinya, sebab secara apriori Lean tidak dapat menebak R yang tepat hanya dari M. Jadi, jika kita mendeklarasikan R sebagai gelanggang dan M sebagai modul atas R, kita harus mendeklarasikan M sebagai AddCommGroup atau menambahkan instans tersebut ke konteks secara manual:

example {R : Type*} [Ring R] {M : Type*} [AddCommMonoid M] [Module R M] : M  M :=
  -- Pastikan menggunakan `letI` (bukan `haveI` atau `let`) agar struktur aditif
  -- yang sudah ada dari hipotesis `AddCommMonoid M` lebih mudah diidentifikasi
  -- dengan struktur baru yang diperkenalkan pada baris berikutnya.
  letI : AddCommGroup M := Module.addCommMonoidToAddCommGroup R
  fun x => - x

10.1.2. Pemetaan linear

Selanjutnya, kita memerlukan pemetaan linear. Seperti morfisme grup, pemetaan linear dalam Mathlib merupakan pemetaan terbundel, yakni paket yang terdiri atas sebuah pemetaan dan bukti sifat-sifat linearitasnya. Pemetaan terbundel tersebut dikonversi menjadi fungsi biasa ketika diterapkan. Lihat Bab 8 untuk informasi lebih lanjut mengenai rancangan ini.

Tipe pemetaan linear di antara dua ruang vektor-K, V dan W, dinotasikan sebagai V →ₗ[K] W. Subskrip l berarti linear. Pada mulanya, pencantuman K dalam notasi ini mungkin terasa ganjil, tetapi hal itu sangat penting ketika beberapa medan terlibat. Sebagai contoh, semua pemetaan yang linear atas bilangan real dari \(ℂ\) ke \(ℂ\) berbentuk \(z ↦ az + b\bar{z}\), sedangkan hanya pemetaan berbentuk \(z ↦ az\) yang linear atas bilangan kompleks. Perbedaan ini sangat penting dalam analisis kompleks.

variable {W : Type*} [AddCommGroup W] [Module K W]

variable (φ : V →ₗ[K] W)

example (a : K) (v : V) : φ (a  v) = a  φ v :=
  map_smul φ a v

example (v w : V) : φ (v + w) = φ v + φ w :=
  map_add φ v w

Perhatikan bahwa V →ₗ[K] W sendiri memiliki struktur aljabar yang menarik (inilah salah satu alasan pemetaan tersebut dibundel). Tipe ini merupakan ruang vektor-K, sehingga kita dapat menjumlahkan pemetaan linear dan mengalikannya dengan skalar.

variable (ψ : V →ₗ[K] W)

#check (2  φ + ψ : V →ₗ[K] W)

Salah satu kekurangan pemetaan terbundel ialah komposisi fungsi biasa tidak dapat digunakan. Kita perlu memakai LinearMap.comp atau notasi ∘ₗ.

variable (θ : W →ₗ[K] V)

#check (φ.comp θ : W →ₗ[K] W)
#check (φ ∘ₗ θ : W →ₗ[K] W)

Ada dua cara utama untuk membangun pemetaan linear. Pertama, kita dapat membangun strukturnya dengan memberikan fungsi beserta bukti linearitasnya. Seperti biasa, tindakan kode untuk struktur memudahkan hal ini: Anda dapat mengetik example : V →ₗ[K] V := _ lalu menggunakan tindakan kode “Generate a skeleton” (buat kerangka) yang terlampir pada garis bawah tersebut.

example : V →ₗ[K] V where
  toFun v := 3  v
  map_add' _ _ := smul_add ..
  map_smul' _ _ := smul_comm ..

Anda mungkin bertanya-tanya mengapa nama komponen bukti pada LinearMap berakhiran tanda prima. Penyebabnya, komponen tersebut didefinisikan sebelum koersi ke fungsi didefinisikan, sehingga pernyataannya menggunakan LinearMap.toFun. Setelah itu, komponen tersebut dinyatakan ulang sebagai LinearMap.map_add dan LinearMap.map_smul dengan menggunakan koersi ke fungsi.

Namun, ceritanya belum berakhir. Kita juga menginginkan versi map_add yang berlaku bagi setiap pemetaan (terbundel) yang mempertahankan penjumlahan, seperti morfisme grup aditif, pemetaan linear, pemetaan linear kontinu, pemetaan aljabar-K, dan sebagainya. Versi tersebut adalah map_add (dalam namespace akar). Versi antara, LinearMap.map_add, agak redundan, tetapi memungkinkan penggunaan notasi titik, yang kadang-kadang nyaman. Kisah serupa berlaku bagi map_smul, dan kerangka umumnya dijelaskan dalam Bab 8.

#check (φ.map_add' :  x y : V, φ.toFun (x + y) = φ.toFun x + φ.toFun y)
#check (φ.map_add :  x y : V, φ (x + y) = φ x + φ y)
#check (map_add φ :  x y : V, φ (x + y) = φ x + φ y)

Kita juga dapat membangun pemetaan linear dari pemetaan yang telah didefinisikan dalam Mathlib dengan menggunakan berbagai kombinator. Sebagai contoh, pemetaan pada contoh di atas telah dikenal sebagai LinearMap.lsmul K V 3. Ada beberapa alasan mengapa K dan V menjadi argumen eksplisit di sini. Alasan yang paling mendesak ialah bahwa dari LinearMap.lsmul 3 saja, Lean sama sekali tidak dapat menyimpulkan V, bahkan K. Selain itu, LinearMap.lsmul K V merupakan objek yang menarik dengan sendirinya: tipenya adalah K →ₗ[K] V →ₗ[K] V, yang berarti bahwa objek tersebut merupakan pemetaan linear-K dari K—dipandang sebagai ruang vektor atas dirinya sendiri—ke ruang pemetaan linear-K dari V ke V.

#check (LinearMap.lsmul K V 3 : V →ₗ[K] V)
#check (LinearMap.lsmul K V : K →ₗ[K] V →ₗ[K] V)

Terdapat pula tipe isomorfisme linear LinearEquiv, yang dinotasikan sebagai V ≃ₗ[K] W. Invers dari f : V ≃ₗ[K] W adalah f.symm : W ≃ₗ[K] V; komposisi f dan g adalah f.trans g, yang juga dinotasikan sebagai f ≪≫ₗ g; dan isomorfisme identitas pada V adalah LinearEquiv.refl K V. Elemen tipe ini secara otomatis dikoersikan menjadi morfisme dan fungsi ketika diperlukan.

example (f : V ≃ₗ[K] W) : f ≪≫ₗ f.symm = LinearEquiv.refl K V :=
  f.self_trans_symm

LinearEquiv.ofBijective dapat digunakan untuk membangun isomorfisme dari morfisme bijektif. Dengan cara ini, fungsi inversnya menjadi tidak dapat dihitung.

noncomputable example (f : V →ₗ[K] W) (h : Function.Bijective f) : V ≃ₗ[K] W :=
  .ofBijective f h

Perhatikan bahwa dalam contoh di atas, Lean menggunakan tipe yang telah dinyatakan untuk memahami bahwa .ofBijective merujuk pada LinearEquiv.ofBijective (tanpa perlu membuka namespace apa pun).

10.1.3. Jumlah dan produk ruang vektor

Kita dapat membangun ruang vektor baru dari ruang yang telah ada dengan menggunakan jumlah langsung dan produk langsung. Mari kita mulai dengan dua ruang vektor. Dalam kasus ini, tidak ada perbedaan antara jumlah dan produk, sehingga kita cukup menggunakan tipe produk. Cuplikan kode berikut menunjukkan cara memperoleh semua pemetaan struktur (inklusi dan proyeksi) sebagai pemetaan linear, serta sifat universal yang membangun pemetaan linear menuju produk dan keluar dari jumlah. (Jika Anda belum mengenal perbedaan antara jumlah dan produk dari sudut pandang teori kategori, abaikan saja istilah sifat universal dan perhatikan tipe contoh-contoh berikut.)

section binary_product

variable {W : Type*} [AddCommGroup W] [Module K W]
variable {U : Type*} [AddCommGroup U] [Module K U]
variable {T : Type*} [AddCommGroup T] [Module K T]

  -- Pemetaan proyeksi pertama
example : V × W →ₗ[K] V := LinearMap.fst K V W

  -- Pemetaan proyeksi kedua
example : V × W →ₗ[K] W := LinearMap.snd K V W

  -- Sifat universal produk
example (φ : U →ₗ[K] V) (ψ : U →ₗ[K] W) : U →ₗ[K]  V × W := LinearMap.prod φ ψ

  -- Pemetaan produk bekerja sebagaimana diharapkan pada komponen pertama
example (φ : U →ₗ[K] V) (ψ : U →ₗ[K] W) : LinearMap.fst K V W ∘ₗ LinearMap.prod φ ψ = φ := rfl

  -- Pemetaan produk bekerja sebagaimana diharapkan pada komponen kedua
example (φ : U →ₗ[K] V) (ψ : U →ₗ[K] W) : LinearMap.snd K V W ∘ₗ LinearMap.prod φ ψ = ψ := rfl

  -- Kita juga dapat menggabungkan pemetaan secara paralel
example (φ : V →ₗ[K] U) (ψ : W →ₗ[K] T) : (V × W) →ₗ[K] (U × T) := φ.prodMap ψ

  -- Hal ini cukup dilakukan dengan menggabungkan proyeksi dan sifat universal
example (φ : V →ₗ[K] U) (ψ : W →ₗ[K] T) :
  φ.prodMap ψ = (φ ∘ₗ .fst K V W).prod (ψ ∘ₗ .snd K V W) := rfl

  -- Pemetaan inklusi pertama
example : V →ₗ[K] V × W := LinearMap.inl K V W

  -- Pemetaan inklusi kedua
example : W →ₗ[K] V × W := LinearMap.inr K V W

  -- Sifat universal jumlah (alias koproduk)
example (φ : V →ₗ[K] U) (ψ : W →ₗ[K] U) : V × W →ₗ[K] U := φ.coprod ψ

  -- Pemetaan koproduk bekerja sebagaimana diharapkan pada komponen pertama
example (φ : V →ₗ[K] U) (ψ : W →ₗ[K] U) : φ.coprod ψ ∘ₗ LinearMap.inl K V W = φ :=
  LinearMap.coprod_inl φ ψ

  -- Pemetaan koproduk bekerja sebagaimana diharapkan pada komponen kedua
example (φ : V →ₗ[K] U) (ψ : W →ₗ[K] U) : φ.coprod ψ ∘ₗ LinearMap.inr K V W = ψ :=
  LinearMap.coprod_inr φ ψ

  -- Pemetaan koproduk didefinisikan sebagaimana yang diharapkan
example (φ : V →ₗ[K] U) (ψ : W →ₗ[K] U) (v : V) (w : W) :
    φ.coprod ψ (v, w) = φ v + ψ w :=
  rfl

end binary_product

Sekarang mari kita beralih ke jumlah dan produk dari sembarang keluarga ruang vektor. Kita akan melihat cara mendefinisikan keluarga ruang vektor dan mengakses sifat universal jumlah serta produk. Perhatikan bahwa notasi jumlah langsung berada dalam lingkup namespace DirectSum dan bahwa sifat universal jumlah langsung memerlukan kesamaan yang dapat diputuskan pada tipe indeks (ini sekadar kekhasan implementasi).

section families
open DirectSum

variable {ι : Type*} [DecidableEq ι]
         (V : ι  Type*) [ i, AddCommGroup (V i)] [ i, Module K (V i)]

-- Sifat universal jumlah langsung merakit pemetaan dari suku-sukunya untuk
-- membangun pemetaan dari jumlah langsung
example (φ : Π i, (V i →ₗ[K] W)) : ( i, V i) →ₗ[K] W :=
  DirectSum.toModule K ι W φ

-- Sifat universal produk langsung merakit pemetaan menuju faktor-faktornya untuk
-- membangun pemetaan menuju produk langsung
example (φ : Π i, (W →ₗ[K] V i)) : W →ₗ[K] (Π i, V i) :=
  LinearMap.pi φ

-- Pemetaan proyeksi dari produk
example (i : ι) : (Π j, V j) →ₗ[K] V i := LinearMap.proj i

-- Pemetaan inklusi menuju jumlah
example (i : ι) : V i →ₗ[K] ( i, V i) := DirectSum.lof K ι V i

-- Pemetaan inklusi menuju produk
example (i : ι) : V i →ₗ[K] (Π i, V i) := LinearMap.single K V i

-- Jika `ι` merupakan tipe hingga, terdapat isomorfisme antara jumlah dan produk.
example [Fintype ι] : ( i, V i) ≃ₗ[K] (Π i, V i) :=
  linearEquivFunOnFintype K ι V

end families

10.2. Subruang dan ruang hasil bagi

10.2.1. Subruang

Seperti pemetaan linear yang dibundel, subruang linear dari V juga merupakan struktur terbundel. Struktur ini terdiri atas sebuah himpunan bagian dari V, yang disebut himpunan pembawa subruang, beserta sifat-sifat ketertutupan yang relevan. Sekali lagi, istilah modul muncul alih-alih ruang vektor karena Mathlib sebenarnya menggunakan konteks yang lebih umum bagi aljabar linear.

section
variable {K : Type*} [Field K] {V : Type*} [AddCommGroup V] [Module K V]

example (U : Submodule K V) {x y : V} (hx : x  U) (hy : y  U) :
    x + y  U :=
  U.add_mem hx hy

example (U : Submodule K V) {x : V} (hx : x  U) (a : K) :
    a  x  U :=
  U.smul_mem a hx
end

Dalam contoh di atas, penting untuk memahami bahwa Submodule K V merupakan tipe subruang linear-K dari V, bukan predikat IsSubmodule U dengan U sebagai elemen Set V. Submodule K V dilengkapi koersi ke Set V dan predikat keanggotaan pada V. Lihat Bab 8.3 untuk penjelasan mengenai bagaimana dan mengapa hal ini dilakukan.

Tentu saja, dua subruang sama jika dan hanya jika keduanya memiliki elemen yang sama. Fakta ini didaftarkan agar dapat digunakan oleh taktik ext. Taktik tersebut dapat membuktikan kesamaan dua subruang dengan cara yang sama seperti ketika membuktikan kesamaan dua himpunan.

Sebagai contoh, untuk menyatakan dan membuktikan bahwa merupakan subruang linear- dari , yang sebenarnya ingin kita lakukan ialah membangun term bertipe Submodule yang proyeksinya ke Set adalah , atau lebih tepatnya, citra dalam .

noncomputable example : Submodule   where
  carrier := Set.range (() :   )
  add_mem' := by
    rintro _ _ n, rfl m, rfl
    use n + m
    simp
  zero_mem' := by
    use 0
    simp
  smul_mem' := by
    rintro c - a, rfl
    use c*a
    simp

Tanda prima di akhir komponen bukti dalam Submodule serupa dengan tanda prima dalam LinearMap. Komponen tersebut dinyatakan menggunakan komponen carrier karena didefinisikan sebelum instans Membership. Setelah itu, perannya digantikan oleh Submodule.add_mem, Submodule.zero_mem, dan Submodule.smul_mem yang telah kita lihat di atas.

Sebagai latihan memanipulasi subruang dan pemetaan linear, Anda akan mendefinisikan prapeta suatu subruang oleh pemetaan linear. (Tentu saja, nanti kita akan melihat bahwa hal ini sudah tersedia di Mathlib.) Ingat bahwa Set.mem_preimage dapat digunakan untuk menulis ulang pernyataan yang melibatkan keanggotaan dan prapeta. Inilah satu-satunya lemma tambahan yang diperlukan selain lemma mengenai LinearMap dan Submodule yang telah dibahas di atas.

variable {K : Type*} [Field K] {V : Type*} [AddCommGroup V] [Module K V]

def preimage {W : Type*} [AddCommGroup W] [Module K W] (φ : V →ₗ[K] W) (H : Submodule K W) :
    Submodule K V where
  carrier := φ ⁻¹' H
  zero_mem' := by
    sorry
  add_mem' := by
    sorry
  smul_mem' := by
    sorry

Melalui kelas tipe, Mathlib mengetahui bahwa subruang dari ruang vektor mewarisi struktur ruang vektor.

example (U : Submodule K V) : Module K U := inferInstance

Contoh ini memiliki seluk-beluk. Objek U bukan sebuah tipe, tetapi Lean secara otomatis mengkoersikannya menjadi tipe dengan menafsirkannya sebagai subtipe dari V. Karena itu, contoh di atas dapat dinyatakan ulang secara lebih eksplisit sebagai:

example (U : Submodule K V) : Module K {x : V // x  U} := inferInstance

10.2.2. Struktur kekisi lengkap dan jumlah langsung internal

Manfaat penting dari tipe Submodule K V alih-alih predikat IsSubmodule : Set V Prop ialah bahwa Submodule K V dapat dengan mudah dilengkapi struktur tambahan. Secara khusus, tipe ini memiliki struktur kekisi lengkap terhadap inklusi. Sebagai contoh, alih-alih memakai lemma yang menyatakan bahwa irisan dua subruang dari V kembali merupakan subruang, kita menggunakan operasi kekisi untuk membangun irisannya. Setelah itu, sembarang lemma mengenai kekisi dapat diterapkan pada konstruksi tersebut.

Mari kita periksa bahwa himpunan yang mendasari infimum dua subruang memang, menurut definisi, merupakan irisan keduanya.

example (H H' : Submodule K V) :
    ((H  H' : Submodule K V) : Set V) = (H : Set V)  (H' : Set V) := rfl

Penggunaan notasi yang berbeda bagi sesuatu yang pada dasarnya merupakan irisan himpunan pembawanya mungkin tampak ganjil. Namun, korespondensi tersebut tidak berlaku bagi operasi supremum dan gabungan himpunan karena, secara umum, gabungan subruang bukanlah subruang. Sebagai gantinya, kita perlu memakai subruang yang direntang oleh gabungan tersebut melalui Submodule.span.

example (H H' : Submodule K V) :
    ((H  H' : Submodule K V) : Set V) = Submodule.span K ((H : Set V)  (H' : Set V)) := by
  simp [Submodule.span_union]

Seluk-beluk lainnya ialah bahwa V sendiri tidak bertipe Submodule K V. Karena itu, kita memerlukan cara untuk membicarakan V yang dipandang sebagai subruang dari V. Hal ini juga disediakan oleh struktur kekisi: subruang penuh merupakan elemen teratas kekisi tersebut.

example (x : V) : x  ( : Submodule K V) := trivial

Serupa dengan itu, elemen terbawah kekisi ini adalah subruang yang satu-satunya elemennya ialah elemen nol.

example (x : V) : x  ( : Submodule K V)  x = 0 := Submodule.mem_bot K

Secara khusus, kita dapat membahas subruang-subruang yang membentuk jumlah langsung (internal). Untuk dua subruang, kita menggunakan predikat serbaguna IsCompl, yang bermakna bagi setiap tipe dengan tatanan parsial berbatas. Untuk keluarga subruang umum, kita menggunakan DirectSum.IsInternal.

-- Jika dua subruang berada dalam jumlah langsung, keduanya merentang seluruh ruang.
example (U V : Submodule K V) (h : IsCompl U V) :
  U  V =  := h.sup_eq_top

-- Jika dua subruang berada dalam jumlah langsung, irisannya hanya memuat nol.
example (U V : Submodule K V) (h : IsCompl U V) :
  U  V =  := h.inf_eq_bot

section
open DirectSum
variable {ι : Type*} [DecidableEq ι]

-- Jika subruang-subruang berada dalam jumlah langsung, semuanya merentang seluruh ruang.
example (U : ι  Submodule K V) (h : DirectSum.IsInternal U) :
   i, U i =  := h.submodule_iSup_eq_top

-- Jika subruang-subruang berada dalam jumlah langsung, irisan berpasangannya hanya memuat nol.
example {ι : Type*} [DecidableEq ι] (U : ι  Submodule K V) (h : DirectSum.IsInternal U)
    {i j : ι} (hij : i  j) : U i  U j =  :=
  (h.submodule_iSupIndep.pairwiseDisjoint hij).eq_bot

-- Syarat-syarat tersebut mencirikan jumlah langsung.
#check DirectSum.isInternal_submodule_iff_iSupIndep_and_iSup_eq_top

-- Hubungannya dengan jumlah langsung eksternal: jika suatu keluarga subruang berada
-- dalam jumlah langsung internal, pemetaan dari jumlah langsung eksternalnya ke `V`
-- merupakan isomorfisme linear.
noncomputable example {ι : Type*} [DecidableEq ι] (U : ι  Submodule K V)
    (h : DirectSum.IsInternal U) : ( i, U i) ≃ₗ[K] V :=
  LinearEquiv.ofBijective (coeLinearMap U) h
end

10.2.3. Subruang yang direntang oleh himpunan

Selain membangun subruang dari subruang yang telah ada, kita dapat membangunnya dari sembarang himpunan s menggunakan Submodule.span K s, yang menghasilkan subruang terkecil yang memuat s. Di atas kertas, lazim digunakan fakta bahwa ruang ini terdiri atas semua kombinasi linear elemen s. Namun, sering kali lebih efisien menggunakan sifat universalnya yang dinyatakan oleh Submodule.span_le beserta seluruh teori koneksi Galois.

example {s : Set V} (E : Submodule K V) : Submodule.span K s  E  s  E :=
  Submodule.span_le

example : GaloisInsertion (Submodule.span K) (() : Submodule K V  Set V) :=
  Submodule.gi K V

Jika semua itu belum cukup, kita dapat menggunakan prinsip induksi yang relevan, Submodule.span_induction. Prinsip ini memastikan bahwa suatu sifat berlaku bagi setiap elemen rentangan s, asalkan sifat tersebut berlaku pada zero dan elemen-elemen s serta stabil terhadap penjumlahan dan perkalian skalar.

Sebagai latihan, mari kita buktikan kembali salah satu arah implikasi Submodule.mem_sup. Ingat bahwa taktik module dapat digunakan untuk menutup sasaran yang mengikuti aksioma yang menghubungkan berbagai operasi aljabar pada V.

example {S T : Submodule K V} {x : V} (h : x  S  T) :
     s  S,  t  T, x = s + t  := by
  rw [ S.span_eq,  T.span_eq,  Submodule.span_union] at h
  induction h using Submodule.span_induction with
  | mem y h =>
      sorry
  | zero =>
      sorry
  | add x y hx hy hx' hy' =>
      sorry
  | smul a x hx hx' =>
      sorry

10.2.4. Mengambil citra dan prapeta subruang

Seperti yang dijanjikan sebelumnya, sekarang kita menjelaskan cara mengambil citra dan prapeta subruang melalui pemetaan linear. Seperti biasa dalam Mathlib, operasi pertama disebut map dan operasi kedua disebut comap.

section

variable {W : Type*} [AddCommGroup W] [Module K W] (φ : V →ₗ[K] W)

variable (E : Submodule K V) in
#check (Submodule.map φ E : Submodule K W)

variable (F : Submodule K W) in
#check (Submodule.comap φ F : Submodule K V)

Perhatikan bahwa keduanya berada dalam namespace Submodule, sehingga notasi titik dapat digunakan untuk menulis E.map φ alih-alih Submodule.map φ E. Namun, bentuk ini cukup janggal untuk dibaca (meski sebagian kontributor Mathlib menggunakannya).

Secara khusus, citra dan kernel pemetaan linear merupakan subruang. Kasus khusus tersebut cukup penting sehingga memiliki deklarasi tersendiri.

example : LinearMap.range φ = .map φ  := LinearMap.range_eq_map φ

example : LinearMap.ker φ = .comap φ  := Submodule.comap_bot φ -- atau `rfl`

Perhatikan bahwa φ.ker tidak dapat ditulis sebagai pengganti LinearMap.ker φ. Penyebabnya, LinearMap.ker juga berlaku bagi kelas pemetaan yang mempertahankan lebih banyak struktur, sehingga tidak mengharapkan argumen yang tipenya diawali LinearMap. Oleh sebab itu, notasi titik tidak bekerja di sini. Namun, kita dapat menggunakan bentuk notasi titik yang lain pada ruas kanan. Setelah mengelaborasi ruas kiri, Lean mengharapkan term bertipe Submodule K V, sehingga .comap ditafsirkan sebagai Submodule.comap.

Lemma-lemma berikut memberikan hubungan utama antara subruang-subruang tersebut dan sifat-sifat φ.

open Function LinearMap

example : Injective φ  ker φ =  := ker_eq_bot.symm

example : Surjective φ  range φ =  := range_eq_top.symm

Sebagai latihan, mari kita buktikan sifat koneksi Galois bagi map dan comap. Lemma-lemma berikut dapat digunakan, tetapi tidak diperlukan karena berlaku menurut definisi.

#check Submodule.mem_map_of_mem
#check Submodule.mem_map
#check Submodule.mem_comap

example (E : Submodule K V) (F : Submodule K W) :
    Submodule.map φ E  F  E  Submodule.comap φ F := by
  sorry

10.2.5. Ruang hasil bagi

Ruang vektor hasil bagi menggunakan notasi hasil bagi umum (diketik dengan \quot, bukan / biasa). Proyeksi ke ruang hasil bagi adalah Submodule.mkQ, sedangkan sifat universalnya adalah Submodule.liftQ.

variable (E : Submodule K V)

example : Module K (V  E) := inferInstance

example : V →ₗ[K] V  E := E.mkQ

example : ker E.mkQ = E := E.ker_mkQ

example : range E.mkQ =  := E.range_mkQ

example ( : E  ker φ) : V  E →ₗ[K] W := E.liftQ φ 

example (F : Submodule K W) ( : E  .comap φ F) : V  E →ₗ[K] W  F := E.mapQ F φ 

noncomputable example : (V  LinearMap.ker φ) ≃ₗ[K] range φ := φ.quotKerEquivRange

Sebagai latihan, mari kita buktikan teorema korespondensi bagi subruang dari ruang hasil bagi. Mathlib mengenal versi yang sedikit lebih presisi sebagai Submodule.comapMkQRelIso.

open Submodule

#check Submodule.map_comap_eq
#check Submodule.comap_map_eq

example : Submodule K (V  E)  { F : Submodule K V // E  F } where
  toFun := sorry
  invFun := sorry
  left_inv := sorry
  right_inv := sorry

10.3. Endomorfisme

Kasus khusus penting dari pemetaan linear ialah endomorfisme: pemetaan linear dari ruang vektor ke dirinya sendiri. Endomorfisme menarik karena membentuk aljabar-K. Secara khusus, kita dapat mengevaluasi polinomial berkoefisien dalam K pada endomorfisme, dan endomorfisme dapat memiliki nilai eigen serta vektor eigen.

Mathlib menggunakan singkatan Module.End K V := V →ₗ[K] V, yang praktis ketika kita banyak menggunakannya (terutama setelah membuka namespace Module).

variable {K : Type*} [Field K] {V : Type*} [AddCommGroup V] [Module K V]

variable {W : Type*} [AddCommGroup W] [Module K W]


open Polynomial Module LinearMap End

example (φ ψ : End K V) : φ * ψ = φ ∘ₗ ψ :=
  End.mul_eq_comp φ ψ -- `rfl` juga dapat digunakan

-- mengevaluasi `P` pada `φ`
example (P : K[X]) (φ : End K V) : V →ₗ[K] V :=
  aeval φ P

-- mengevaluasi `X` pada `φ` menghasilkan kembali `φ`
example (φ : End K V) : aeval φ (X : K[X]) = φ :=
  aeval_X φ

Sebagai latihan memanipulasi endomorfisme, subruang, dan polinomial, mari kita buktikan lemma kernel (biner): untuk setiap endomorfisme \(φ\) dan setiap pasangan polinomial relatif prima \(P\) dan \(Q\), berlaku \(\ker P(φ) ⊕ \ker Q(φ) = \ker \big(PQ(φ)\big)\).

Perhatikan bahwa IsCoprime x y didefinisikan sebagai a b, a * x + b * y = 1.

#check Submodule.eq_bot_iff
#check Submodule.mem_inf
#check LinearMap.mem_ker

example (P Q : K[X]) (h : IsCoprime P Q) (φ : End K V) : ker (aeval φ P)  ker (aeval φ Q) =  := by
  sorry

#check Submodule.add_mem_sup
#check map_mul
#check End.mul_apply
#check LinearMap.ker_le_ker_comp

example (P Q : K[X]) (h : IsCoprime P Q) (φ : End K V) :
    ker (aeval φ P)  ker (aeval φ Q) = ker (aeval φ (P*Q)) := by
  sorry

Sekarang kita beralih ke pembahasan ruang eigen dan nilai eigen. Ruang eigen yang berkaitan dengan endomorfisme \(φ\) dan skalar \(a\) adalah kernel dari \(φ - aId\). Ruang eigen didefinisikan bagi semua nilai a, meskipun ruang tersebut hanya menarik ketika tidak nol. Namun, menurut definisi, vektor eigen merupakan elemen tak nol dari ruang eigen. Predikat yang bersesuaian adalah End.HasEigenvector.

example (φ : End K V) (a : K) : φ.eigenspace a = LinearMap.ker (φ - a  1) :=
  End.eigenspace_def

Selanjutnya, terdapat predikat End.HasEigenvalue dan subtipe yang bersesuaian, End.Eigenvalues.

example (φ : End K V) (a : K) : φ.HasEigenvalue a  φ.eigenspace a   :=
  Iff.rfl

example (φ : End K V) (a : K) : φ.HasEigenvalue a   v, φ.HasEigenvector a v  :=
  End.HasEigenvalue.exists_hasEigenvector, fun _, hv  φ.hasEigenvalue_of_hasEigenvector hv

example (φ : End K V) : φ.Eigenvalues = {a // φ.HasEigenvalue a} :=
  rfl

-- Nilai eigen merupakan akar polinomial minimal
example (φ : End K V) (a : K) : φ.HasEigenvalue a  (minpoly K φ).IsRoot a :=
  φ.isRoot_of_hasEigenvalue

-- Dalam dimensi hingga, konversnya juga berlaku (dimensi akan dibahas di bawah)
example [FiniteDimensional K V] (φ : End K V) (a : K) :
    φ.HasEigenvalue a  (minpoly K φ).IsRoot a :=
  φ.hasEigenvalue_iff_isRoot

-- Cayley–Hamilton
example [FiniteDimensional K V] (φ : End K V) : aeval φ φ.charpoly = 0 :=
  φ.aeval_self_charpoly

10.4. Matriks, basis, dan dimensi

10.4.1. Matriks

Sebelum memperkenalkan basis bagi ruang vektor abstrak, kita kembali ke konteks aljabar linear yang jauh lebih elementer dalam \(K^n\) untuk suatu medan \(K\). Objek utamanya adalah vektor dan matriks. Bagi vektor konkret, kita dapat menggunakan notasi ![…], dengan komponen yang dipisahkan oleh koma. Bagi matriks konkret, kita dapat menggunakan notasi !![…]; baris dipisahkan oleh titik koma, sedangkan elemen dalam setiap baris dipisahkan oleh koma. Jika entri-entri memiliki tipe yang dapat dihitung, seperti atau , kita dapat menggunakan perintah #eval untuk bereksperimen dengan operasi dasar.

section matrices

-- Menjumlahkan vektor
#eval ![1, 2] + ![3, 4]  -- ![4, 6]

-- Menjumlahkan matriks
#eval !![1, 2; 3, 4] + !![3, 4; 5, 6]  -- !![4, 6; 8, 10]

-- Mengalikan matriks
#eval !![1, 2; 3, 4] * !![3, 4; 5, 6]  -- !![13, 16; 29, 36]

Penting untuk dipahami bahwa penggunaan #eval ini hanya berguna bagi eksplorasi; tujuannya bukan menggantikan sistem aljabar komputer seperti Sage. Representasi data matriks yang digunakan di sini sama sekali tidak efisien secara komputasional. Representasi tersebut menggunakan fungsi alih-alih larik dan dioptimalkan untuk pembuktian, bukan perhitungan. Mesin virtual yang digunakan oleh #eval juga tidak dioptimalkan untuk keperluan ini.

Perhatikan bahwa notasi matriks mencantumkan baris-barisnya, sedangkan notasi vektor tidak menyatakan vektor baris maupun vektor kolom. Perkalian vektor dengan matriks dari sebelah kiri (atau kanan) menafsirkan vektor tersebut sebagai vektor baris (atau kolom). Hal ini bersesuaian dengan operasi Matrix.vecMul bernotasi ᵥ* dan Matrix.mulVec bernotasi *ᵥ. Kedua notasi tersebut berada dalam lingkup namespace Matrix, sehingga namespace itu perlu kita buka.

open Matrix

-- matriks yang beraksi pada vektor dari sebelah kiri
#eval !![1, 2; 3, 4] *ᵥ ![1, 1] -- ![3, 7]

-- aksi matriks pada vektor dari kiri menghasilkan vektor berukuran satu
#eval !![1, 2] *ᵥ ![1, 1]  -- ![3]

-- matriks yang beraksi pada vektor dari sebelah kanan
#eval  ![1, 1, 1] ᵥ* !![1, 2; 3, 4; 5, 6] -- ![9, 12]

Untuk menghasilkan matriks dengan baris-baris atau kolom-kolom identik yang ditentukan oleh sebuah vektor, kita menggunakan Matrix.replicateRow dan Matrix.replicateCol. Argumennya adalah tipe yang mengindeks baris atau kolom serta vektornya. Sebagai contoh, kita dapat memperoleh matriks satu baris atau satu kolom (lebih tepatnya, matriks yang baris atau kolomnya diindeks oleh Fin 1).

#eval replicateRow (Fin 1) ![1, 2] -- !![1, 2]

#eval replicateCol (Fin 1) ![1, 2] -- !![1; 2]

Operasi lain yang tidak asing mencakup hasil kali titik vektor, transpos matriks, serta—bagi matriks persegi—determinan dan jejak.

-- hasil kali titik vektor
#eval ![1, 2] ⬝ᵥ ![3, 4] -- `11`

-- transpos matriks
#eval !![1, 2; 3, 4] -- `!![1, 3; 2, 4]`

-- determinan
#eval !![(1 : ), 2; 3, 4].det -- `-2`

-- jejak
#eval !![(1 : ), 2; 3, 4].trace -- `5`

Jika entri-entri tidak memiliki tipe yang dapat dihitung, misalnya berupa bilangan real, kita tidak dapat mengharapkan bantuan dari #eval. Evaluasi semacam ini juga tidak dapat digunakan dalam pembuktian tanpa memperluas basis kode tepercaya secara substansial (yakni bagian Lean yang perlu Anda percayai ketika memeriksa bukti).

Karena itu, sebaiknya gunakan pula taktik simp dan norm_num dalam pembuktian, atau padanan perintahnya untuk eksplorasi cepat.

#simp !![(1 : ), 2; 3, 4].det -- `4 - 2*3`

#norm_num !![(1 : ), 2; 3, 4].det -- `-2`

#norm_num !![(1 : ), 2; 3, 4].trace -- `5`

variable (a b c d : ) in
#simp !![a, b; c, d].det -- `a * d - b * c`

Operasi penting berikutnya pada matriks persegi ialah inversi. Sama seperti pembagian bilangan yang selalu didefinisikan dan menghasilkan nilai artifisial nol bagi pembagian dengan nol, operasi inversi didefinisikan pada semua matriks dan menghasilkan matriks nol bagi matriks yang tidak dapat dibalik.

Lebih tepatnya, terdapat fungsi umum Ring.inverse yang melakukan hal ini dalam sembarang gelanggang. Bagi setiap matriks A, A⁻¹ didefinisikan sebagai Ring.inverse A.det A.adjugate. Menurut aturan Cramer, nilai tersebut memang merupakan invers A apabila determinan A tidak nol.

#norm_num [Matrix.inv_def] !![(1 : ), 2; 3, 4]⁻¹ -- !![-2, 1; 3 / 2, -(1 / 2)]

Tentu saja, definisi ini benar-benar berguna hanya bagi matriks yang dapat dibalik. Terdapat kelas tipe umum Invertible yang membantu mencatat sifat tersebut. Sebagai contoh, pemanggilan simp dalam contoh berikut akan menggunakan lemma inv_mul_of_invertible, yang memiliki asumsi kelas tipe Invertible. Karena itu, lemma tersebut hanya terpicu apabila asumsi ini dapat ditemukan oleh sistem sintesis kelas tipe. Di sini, kita menyediakan fakta tersebut melalui pernyataan have.

example : !![(1 : ), 2; 3, 4]⁻¹ * !![(1 : ), 2; 3, 4] = 1 := by
  have : Invertible !![(1 : ), 2; 3, 4] := by
    apply Matrix.invertibleOfIsUnitDet
    norm_num
  simp

Dalam kasus yang sepenuhnya konkret ini, kita juga dapat menggunakan mekanisme norm_num dan apply? untuk menemukan baris terakhir:

example : !![(1 : ), 2; 3, 4]⁻¹ * !![(1 : ), 2; 3, 4] = 1 := by
  norm_num [Matrix.inv_def]
  exact one_fin_two.symm

Semua matriks konkret di atas memiliki baris dan kolom yang diindeks oleh Fin n untuk suatu n (yang tidak harus sama bagi baris dan kolom). Namun, kadang-kadang lebih nyaman mengindeks matriks dengan sembarang tipe hingga. Sebagai contoh, baris dan kolom matriks ketetanggaan suatu graf hingga secara alami diindeks oleh simpul graf tersebut.

Sebenarnya, ketika kita sekadar ingin mendefinisikan matriks tanpa mendefinisikan operasi apa pun padanya, tipe indeksnya bahkan tidak perlu hingga dan koefisiennya dapat bertipe apa saja tanpa struktur aljabar. Karena itu, Mathlib cukup mendefinisikan Matrix m n α sebagai m n α bagi sembarang tipe m, n, dan α. Matriks yang telah kita gunakan sejauh ini memiliki tipe seperti Matrix (Fin 2) (Fin 2) . Tentu saja, operasi aljabar memerlukan lebih banyak asumsi atas m, n, dan α.

Perhatikan bahwa alasan utama kita tidak langsung menggunakan m n α ialah agar sistem kelas tipe dapat memahami apa yang kita inginkan. Sebagai contoh, bagi gelanggang R, tipe n R dilengkapi operasi perkalian titik demi titik. Demikian pula, m n R memiliki operasi tersebut, yang bukan perkalian yang kita inginkan pada matriks.

Dalam contoh pertama di bawah, kita memaksa Lean menembus definisi Matrix dan menerima bahwa pernyataannya bermakna, lalu membuktikannya dengan memeriksa semua entri.

Namun, dua contoh berikutnya memperlihatkan bahwa Lean menggunakan perkalian titik demi titik pada Fin 2 Fin 2 , tetapi perkalian matriks pada Matrix (Fin 2) (Fin 2) .

section

example : (fun _  1 : Fin 2  Fin 2  ) = !![1, 1; 1, 1] := by
  ext i j
  fin_cases i <;> fin_cases j <;> rfl

example : (fun _  1 : Fin 2  Fin 2  ) * (fun _  1 : Fin 2  Fin 2  ) = !![1, 1; 1, 1] := by
  ext i j
  fin_cases i <;> fin_cases j <;> rfl

example : !![1, 1; 1, 1] * !![1, 1; 1, 1] = !![2, 2; 2, 2] := by
  norm_num

Untuk mendefinisikan matriks sebagai fungsi tanpa kehilangan manfaat Matrix bagi sintesis kelas tipe, kita dapat menggunakan ekuivalensi Matrix.of antara fungsi dan matriks. Diam-diam, ekuivalensi ini didefinisikan menggunakan Equiv.refl.

Sebagai contoh, kita dapat mendefinisikan matriks Vandermonde yang bersesuaian dengan vektor v.

example {n : } (v : Fin n  ) :
    Matrix.vandermonde v = Matrix.of (fun i j : Fin n  v i ^ (j : )) :=
  rfl
end
end matrices

10.4.2. Basis

Sekarang kita ingin membahas basis ruang vektor. Secara informal, ada banyak cara untuk mendefinisikan gagasan ini. Kita dapat menggunakan sifat universal. Kita dapat mengatakan bahwa basis merupakan keluarga vektor yang bebas linear dan merentang. Kita juga dapat menggabungkan kedua sifat itu dan langsung mengatakan bahwa basis adalah keluarga vektor sedemikian sehingga setiap vektor dapat ditulis secara unik sebagai kombinasi linear vektor-vektor basis. Cara lainnya ialah mengatakan bahwa basis memberikan isomorfisme linear dengan suatu pangkat dari medan dasar K, yang dipandang sebagai ruang vektor atas K.

Versi isomorfisme inilah yang sebenarnya digunakan Mathlib sebagai definisi di balik layar; karakterisasi lainnya dibuktikan darinya. Kita perlu sedikit berhati-hati dengan gagasan “pangkat dari K” dalam kasus basis tak hingga. Dalam konteks aljabar ini, hanya kombinasi linear hingga yang bermakna. Karena itu, ruang vektor acuan yang kita perlukan bukan produk langsung salinan K, melainkan jumlah langsung. Kita dapat menggunakan i : ι, K bagi suatu tipe ι yang mengindeks basis, tetapi sebagai gantinya kita memakai penulisan yang lebih khusus, ι →₀ K. Notasi ini berarti “fungsi dari ι ke K dengan dukungan hingga”, yakni fungsi yang bernilai nol di luar suatu himpunan bagian hingga dari ι (himpunan ini tidak tetap, tetapi bergantung pada fungsinya). Mengevaluasi fungsi semacam itu yang berasal dari basis B pada vektor v dan i : ι menghasilkan komponen (atau koordinat) v pada vektor basis ke-i.

Tipe basis ruang vektor-K V yang diindeks oleh tipe ι adalah Basis ι K V. Isomorfismenya disebut Basis.repr.

variable {K : Type*} [Field K] {V : Type*} [AddCommGroup V] [Module K V]

section

open Module

variable {ι : Type*} (B : Basis ι K V) (v : V) (i : ι)

-- Vektor basis dengan indeks ``i``
#check (B i : V)

-- Isomorfisme linear dengan ruang model yang diberikan oleh ``B``
#check (B.repr : V ≃ₗ[K] ι →₀ K)

-- Fungsi komponen dari ``v``
#check (B.repr v : ι →₀ K)

-- Komponen dari ``v`` dengan indeks ``i``
#check (B.repr v i : K)

Alih-alih memulai dengan isomorfisme semacam itu, kita dapat memulai dengan keluarga vektor b yang bebas linear dan merentang. Konstruksi ini adalah Basis.mk.

Asumsi bahwa keluarga tersebut merentang ditulis sebagai Submodule.span K (Set.range b). Di sini, adalah submodul teratas dari V, yakni V yang dipandang sebagai submodul dari dirinya sendiri. Penulisan ini tampak agak berbelit, tetapi di bawah kita akan melihat bahwa bentuk tersebut hampir ekuivalen menurut definisi dengan bentuk yang lebih mudah dibaca, v, v Submodule.span K (Set.range b). Garis-garis bawah dalam cuplikan berikut merujuk pada informasi v yang tidak berguna.

noncomputable example (b : ι  V) (b_indep : LinearIndependent K b)
    (b_spans :  v, v  Submodule.span K (Set.range b)) : Basis ι K V :=
  Basis.mk b_indep (fun v _  b_spans v)

-- Keluarga vektor yang mendasari basis di atas memang ``b``.
example (b : ι  V) (b_indep : LinearIndependent K b)
    (b_spans :  v, v  Submodule.span K (Set.range b)) (i : ι) :
    Basis.mk b_indep (fun v _  b_spans v) i = b i :=
  Basis.mk_apply b_indep (fun v _  b_spans v) i

Secara khusus, ruang vektor model ι →₀ K memiliki basis yang disebut basis kanonik, dengan fungsi repr yang merupakan isomorfisme identitas dan karenanya mengembalikan setiap vektor tanpa perubahan. Basis ini disebut Finsupp.basisSingleOne. Finsupp berarti fungsi dengan dukungan hingga, sedangkan basisSingleOne merujuk pada fakta bahwa vektor-vektor basisnya berupa fungsi yang bernilai nol kecuali pada satu nilai masukan. Lebih tepatnya, vektor basis yang diindeks oleh i : ι adalah Finsupp.single i 1, yakni fungsi berdukungan hingga yang bernilai 1 pada i dan 0 di semua tempat lain.

variable [DecidableEq ι]
example : Finsupp.basisSingleOne.repr = LinearEquiv.refl K (ι →₀ K) :=
  rfl

example (i : ι) : Finsupp.basisSingleOne i = Finsupp.single i 1 :=
  rfl

Pembahasan fungsi berdukungan hingga tidak diperlukan ketika tipe indeksnya hingga. Dalam kasus ini, kita dapat menggunakan Pi.basisFun yang lebih sederhana dan memberikan basis bagi seluruh ι K.

example [Finite ι] (x : ι  K) (i : ι) : (Pi.basisFun K ι).repr x i = x i := by
  simp

Kembali ke kasus umum basis ruang vektor abstrak, kita dapat menyatakan sembarang vektor sebagai kombinasi linear vektor-vektor basis. Mari kita lihat terlebih dahulu kasus mudah berupa basis hingga.

example [Fintype ι] :  i : ι, B.repr v i  (B i) = v :=
  B.sum_repr v

Apabila ι tidak hingga, pernyataan di atas secara apriori tidak bermakna: kita tidak dapat mengambil jumlah atas ι. Namun, dukungan fungsi yang dijumlahkan bersifat hingga (yakni dukungan B.repr v). Kita perlu menerapkan konstruksi yang memperhitungkan fakta ini. Di sini, Mathlib menggunakan fungsi khusus yang perlu waktu untuk dipahami, yaitu Finsupp.linearCombination (yang dibangun di atas Finsupp.sum yang lebih umum). Jika diberikan fungsi berdukungan hingga c dari tipe ι ke medan dasar K dan sembarang fungsi f dari ι ke V, maka Finsupp.linearCombination K f c adalah jumlah atas dukungan c dari perkalian skalar c i f i. Secara khusus, kita dapat menggantinya dengan jumlah atas sembarang himpunan hingga yang memuat dukungan c.

example (c : ι →₀ K) (f : ι  V) (s : Finset ι) (h : c.support  s) :
    Finsupp.linearCombination K f c =  i  s, c i  f i :=
  Finsupp.linearCombination_apply_of_mem_supported K h

Kita juga dapat mengasumsikan bahwa f berdukungan hingga dan tetap memperoleh jumlah yang terdefinisi dengan baik. Namun, pilihan yang dibuat oleh Finsupp.linearCombination relevan bagi pembahasan basis karena memungkinkan kita menyatakan generalisasi Basis.sum_repr.

example : Finsupp.linearCombination K B (B.repr v) = v :=
  B.linearCombination_repr v

Kita mungkin bertanya-tanya mengapa K menjadi argumen eksplisit di sini, meskipun dapat disimpulkan dari tipe c. Alasannya adalah bahwa Finsupp.linearCombination K f yang diterapkan sebagian merupakan objek yang menarik untuk dikaji tersendiri. Objek tersebut bukan fungsi biasa dari ι →₀ K ke V, melainkan pemetaan linear-K.

variable (f : ι  V) in
#check (Finsupp.linearCombination K f : (ι →₀ K) →ₗ[K] V)

Kembali ke pembahasan matematis, penting untuk memahami bahwa representasi vektor dalam suatu basis kurang berguna dalam matematika terformalisasi daripada yang mungkin Anda bayangkan. Sering kali, lebih efisien menggunakan sifat basis yang lebih abstrak secara langsung. Secara khusus, sifat universal basis yang menghubungkannya dengan objek bebas lain dalam aljabar memungkinkan kita membangun pemetaan linear dengan menentukan citra vektor-vektor basis. Konstruksi ini adalah Basis.constr. Bagi sembarang ruang vektor-K W, basis B memberikan isomorfisme linear Basis.constr B K dari ι W ke V →ₗ[K] W. Isomorfisme ini dicirikan oleh fakta bahwa setiap fungsi u : ι W dipetakan ke pemetaan linear yang mengirim vektor basis B i ke u i bagi setiap i : ι.

section

variable {W : Type*} [AddCommGroup W] [Module K W]
         (φ : V →ₗ[K] W) (u : ι  W)

#check (B.constr K : (ι  W) ≃ₗ[K] (V →ₗ[K] W))

#check (B.constr K u : V →ₗ[K] W)

example (i : ι) : B.constr K u (B i) = u i :=
  B.constr_basis K u i

Sifat ini memang mencirikan konstruksi tersebut karena pemetaan linear ditentukan oleh nilainya pada vektor-vektor basis:

example (φ ψ : V →ₗ[K] W) (h :  i, φ (B i) = ψ (B i)) : φ = ψ :=
  B.ext h

Jika kita juga memiliki basis B' pada ruang sasaran, pemetaan linear dapat diidentifikasi dengan matriks. Identifikasi ini merupakan isomorfisme linear-K.

variable {ι' : Type*} (B' : Basis ι' K W) [Fintype ι] [DecidableEq ι] [Fintype ι'] [DecidableEq ι']

open LinearMap

#check (toMatrix B B' : (V →ₗ[K] W) ≃ₗ[K] Matrix ι' ι K)

open Matrix -- memperoleh akses ke notasi ``*ᵥ`` untuk perkalian matriks dan vektor.

example (φ : V →ₗ[K] W) (v : V) : (toMatrix B B' φ) *ᵥ (B.repr v) = B'.repr (φ v) :=
  toMatrix_mulVec_repr B B' φ v


variable {ι'' : Type*} (B'' : Basis ι'' K W) [Fintype ι''] [DecidableEq ι'']

example (φ : V →ₗ[K] W) : (toMatrix B B'' φ) = (toMatrix B' B'' .id) * (toMatrix B B' φ) := by
  simp

end

Sebagai latihan mengenai topik ini, kita akan membuktikan bagian dari teorema yang menjamin bahwa endomorfisme memiliki determinan yang terdefinisi dengan baik. Secara khusus, kita ingin membuktikan bahwa apabila dua basis diindeks oleh tipe yang sama, matriks representasi sembarang endomorfisme relatif terhadap masing-masing basis memiliki determinan yang sama. Untuk memperoleh hasil lengkap, bukti ini kemudian perlu dilengkapi dengan fakta bahwa semua basis memiliki tipe indeks yang isomorfik.

Tentu saja, Mathlib telah mengetahui hal ini dan simp dapat langsung menutup sasaran. Karena itu, jangan gunakan taktik tersebut terlalu dini; gunakanlah lemma yang disediakan.

open Module LinearMap Matrix

-- Beberapa lemma yang berasal dari fakta bahwa `LinearMap.toMatrix` adalah morfisme aljabar.
#check toMatrix_comp
#check id_comp
#check comp_id
#check toMatrix_id

-- Beberapa lemma yang berasal dari fakta bahwa ``Matrix.det`` adalah morfisme monoid multiplikatif.
#check Matrix.det_mul
#check Matrix.det_one

example [Fintype ι] (B' : Basis ι K V) (φ : End K V) :
    (toMatrix B B φ).det = (toMatrix B' B' φ).det := by
  set M := toMatrix B B φ
  set M' := toMatrix B' B' φ
  set P := (toMatrix B B') LinearMap.id
  set P' := (toMatrix B' B) LinearMap.id
  sorry
end

10.4.3. Dimensi

Kembali ke kasus satu ruang vektor, basis juga berguna untuk mendefinisikan konsep dimensi. Sekali lagi, terdapat kasus elementer berupa ruang vektor berdimensi hingga. Bagi ruang semacam itu, kita mengharapkan dimensi berupa bilangan asli. Dimensi ini diberikan oleh Module.finrank. Fungsi tersebut menerima medan dasar sebagai argumen eksplisit karena suatu grup abelian dapat menjadi ruang vektor atas medan yang berbeda-beda.

section

#check (Module.finrank K V : )

-- `Fin n → K` adalah ruang arketipal berdimensi `n` atas `K`.
example (n : ) : Module.finrank K (Fin n  K) = n :=
  Module.finrank_fin_fun K

-- Dipandang sebagai ruang vektor atas dirinya sendiri, `ℂ` berdimensi satu.
example : Module.finrank   = 1 :=
  Module.finrank_self 

-- Namun, sebagai ruang vektor real, ruang tersebut berdimensi dua.
example : Module.finrank   = 2 :=
  Complex.finrank_real_complex

Perhatikan bahwa Module.finrank didefinisikan bagi setiap ruang vektor. Fungsi ini menghasilkan nol bagi ruang vektor berdimensi tak hingga, sebagaimana pembagian dengan nol menghasilkan nol.

Tentu saja, banyak lemma memerlukan asumsi dimensi hingga. Inilah peran kelas tipe FiniteDimensional. Sebagai contoh, pikirkan bagaimana contoh berikut gagal tanpa asumsi tersebut.

example [FiniteDimensional K V] : 0 < Module.finrank K V  Nontrivial V  :=
  Module.finrank_pos_iff

Dalam pernyataan di atas, Nontrivial V berarti V memiliki setidaknya dua elemen berbeda. Perhatikan bahwa Module.finrank_pos_iff tidak memiliki argumen eksplisit. Hal ini tidak bermasalah ketika digunakan dari kiri ke kanan, tetapi bermasalah ketika digunakan dari kanan ke kiri karena Lean tidak dapat menebak K dari pernyataan Nontrivial V. Dalam kasus tersebut, sintaks argumen bernama berguna setelah kita memeriksa bahwa lemma dinyatakan atas gelanggang bernama R. Jadi, kita dapat menulis:

example [FiniteDimensional K V] (h : 0 < Module.finrank K V) : Nontrivial V := by
  apply (Module.finrank_pos_iff (R := K)).1
  exact h

Penulisan di atas terasa ganjil karena kita telah memiliki h sebagai asumsi, sehingga kita dapat langsung memberikan bukti lengkap Module.finrank_pos_iff.1 h. Namun, teknik tersebut tetap berguna untuk diketahui dalam kasus yang lebih rumit.

Menurut definisi, FiniteDimensional K V dapat disimpulkan dari sembarang basis.

variable {ι : Type*} (B : Module.Basis ι K V)

example [Finite ι] : FiniteDimensional K V := Module.Basis.finiteDimensional_of_finite B

example [FiniteDimensional K V] : Finite ι :=
  (FiniteDimensional.fintypeBasisIndex B).finite
end

Dengan menggunakan fakta bahwa subtipe yang bersesuaian dengan subruang linear memiliki struktur ruang vektor, kita dapat membicarakan dimensi subruang.

section
variable (E F : Submodule K V) [FiniteDimensional K V]

open Module

example : finrank K (E  F : Submodule K V) + finrank K (E  F : Submodule K V) =
    finrank K E + finrank K F :=
  Submodule.finrank_sup_add_finrank_inf_eq E F

example : finrank K E  finrank K V := Submodule.finrank_le E

Dalam pernyataan pertama di atas, tujuan anotasi tipe ialah memastikan bahwa koersi ke Type* tidak terpicu terlalu dini.

Sekarang kita siap mengerjakan latihan mengenai finrank dan subruang.

example (h : finrank K V < finrank K E + finrank K F) :
    Nontrivial (E  F : Submodule K V) := by
  sorry
end

Sekarang mari kita beralih ke kasus umum teori dimensi. Dalam kasus ini, finrank tidak berguna. Namun, bagi setiap dua basis dari ruang vektor yang sama, tetap terdapat bijeksi di antara tipe-tipe yang mengindeks kedua basis tersebut. Karena itu, kita masih dapat berharap mendefinisikan rank sebagai kardinal, yakni elemen dari “hasil bagi koleksi tipe oleh relasi ekuivalensi berupa keberadaan bijeksi”.

Ketika membahas kardinal, semakin sulit untuk mengabaikan persoalan landasan seputar paradoks Russell seperti yang kita lakukan di bagian lain buku ini. Tidak ada tipe yang memuat semua tipe karena hal itu akan menimbulkan inkonsistensi logis. Persoalan ini diselesaikan oleh hierarki semesta, yang biasanya kita coba abaikan.

Setiap tipe memiliki level semesta, dan level-level tersebut berperilaku serupa dengan bilangan asli. Secara khusus, terdapat level ke-0; semesta yang bersesuaian, Type 0, cukup dinotasikan sebagai Type. Semesta ini cukup untuk memuat hampir seluruh matematika klasik. Sebagai contoh, dan bertipe Type. Setiap level u memiliki penerus yang dinotasikan sebagai u + 1, dan Type u bertipe Type (u+1).

Namun, level semesta bukan bilangan asli; sifat dasarnya sangat berbeda dan level semesta tidak memiliki tipe. Secara khusus, Anda tidak dapat menyatakan sesuatu seperti u u + 1 dalam Lean. Tidak ada tipe tempat pernyataan tersebut dapat dibentuk. Bahkan, menyatakan Type u Type (u+1) pun tidak bermakna karena Type u dan Type (u+1) memiliki tipe yang berbeda.

Setiap kali kita menulis Type*, Lean menyisipkan variabel level semesta bernama u_n, dengan n berupa bilangan. Hal ini memungkinkan definisi dan pernyataan berlaku dalam semua semesta.

Jika diberikan level semesta u, kita dapat mendefinisikan relasi ekuivalensi pada Type u yang menyatakan bahwa dua tipe α dan β ekuivalen apabila terdapat bijeksi di antara keduanya. Tipe hasil bagi Cardinal.{u} berada dalam Type (u+1). Kurung kurawal menyatakan variabel semesta. Citra α : Type u dalam hasil bagi ini adalah Cardinal.mk α : Cardinal.{u}.

Namun, kita tidak dapat langsung membandingkan kardinal dalam semesta yang berbeda. Jadi, secara teknis kita tidak dapat mendefinisikan rank ruang vektor V sebagai kardinal semua tipe yang mengindeks basis V. Sebagai gantinya, rank didefinisikan sebagai supremum Module.rank K V dari kardinal semua himpunan bebas linear dalam V. Jika V memiliki level semesta u, rank-nya bertipe Cardinal.{u}.

#check V -- Type u_2
#check Module.rank K V -- Cardinal.{u_2}

Definisi ini tetap dapat dihubungkan dengan basis. Memang, terdapat pula operasi komutatif max pada level semesta. Jika diberikan dua level semesta u dan v, terdapat operasi Cardinal.lift.{u, v} : Cardinal.{v} Cardinal.{max v u} yang memungkinkan kita menempatkan kardinal dalam semesta bersama dan menyatakan teorema dimensi.

universe u v -- `u` dan `v` menyatakan level semesta

variable {ι : Type u} (B : Module.Basis ι K V)
         {ι' : Type v} (B' : Module.Basis ι' K V)

example : Cardinal.lift.{v, u} (.mk ι) = Cardinal.lift.{u, v} (.mk ι') :=
  mk_eq_mk_of_basis B B'

Kita dapat menghubungkan kasus berdimensi hingga dengan pembahasan ini melalui koersi dari bilangan asli ke kardinal hingga (atau lebih tepatnya, kardinal hingga yang berada dalam Cardinal.{v}, dengan v sebagai level semesta dari V).

example [FiniteDimensional K V] :
    (Module.finrank K V : Cardinal) = Module.rank K V :=
  Module.finrank_eq_rank K V