Changes
146 changed files (+26872/-5)
-
MIL (deleted)
-
@@ -1,1 +0,0 @@../src
-
-
-
@@ -0,0 +1,2 @@#eval "Hello, World!"
-
-
-
@@ -0,0 +1,57 @@import Mathlib.Data.Nat.Basic import Mathlib.Data.Nat.Parity import Mathlib.Tactic open Nat -- These are pieces of data. #check 2 + 2 def f (x : ℕ) := x + 3 #check f -- These are propositions, of type `Prop`. #check 2 + 2 = 4 def FermatLastTheorem := ∀ x y z n : ℕ, n > 2 ∧ x * y * z ≠ 0 → x ^ n + y ^ n ≠ z ^ n #check FermatLastTheorem -- These are proofs of propositions. theorem easy : 2 + 2 = 4 := rfl #check easy theorem hard : FermatLastTheorem := sorry #check hard -- Here are some proofs. example : ∀ m n : Nat, Even n → Even (m * n) := fun m n ⟨k, (hk : n = k + k)⟩ => have hmn : m * n = m * k + m * k := by rw [hk, mul_add] show ∃ l, m * n = l + l from ⟨_, hmn⟩ example : ∀ m n : Nat, Even n → Even (m * n) := fun m n ⟨k, hk⟩ => ⟨m * k, by rw [hk, mul_add]⟩ example : ∀ m n : Nat, Even n → Even (m * n) := by -- say m and n are natural numbers, and assume n=2*k rintro m n ⟨k, hk⟩ -- We need to prove m*n is twice a natural number. Let's show it's twice m*k. use m * k -- substitute in for n rw [hk] -- and now it's obvious ring example : ∀ m n : Nat, Even n → Even (m * n) := by rintro m n ⟨k, hk⟩; use m * k; rw [hk]; ring example : ∀ m n : Nat, Even n → Even (m * n) := by intros; simp [*, parity_simps]
-
-
-
-
@@ -0,0 +1,7 @@import Mathlib.Data.Nat.Basic import Mathlib.Data.Nat.Parity import Mathlib.Tactic open Nat -- There are no exercises in this section.
-
-
-
@@ -0,0 +1,147 @@import Mathlib.Data.Real.Basic import Mathlib.Data.Real.Basic -- An example. example (a b c : ℝ) : a * b * c = b * (a * c) := by rw [mul_comm a b] rw [mul_assoc b a c] -- Try these. example (a b c : ℝ) : c * b * a = b * (a * c) := by sorry example (a b c : ℝ) : a * (b * c) = b * (a * c) := by sorry -- An example. example (a b c : ℝ) : a * b * c = b * c * a := by rw [mul_assoc] rw [mul_comm] /- Try doing the first of these without providing any arguments at all, and the second with only one argument. -/ example (a b c : ℝ) : a * (b * c) = b * (c * a) := by sorry example (a b c : ℝ) : a * (b * c) = b * (a * c) := by sorry -- Using facts from the local context. example (a b c d e f : ℝ) (h : a * b = c * d) (h' : e = f) : a * (b * e) = c * (d * f) := by rw [h'] rw [← mul_assoc] rw [h] rw [mul_assoc] example (a b c d e f : ℝ) (h : b * c = e * f) : a * b * c * d = a * e * f * d := by sorry example (a b c d : ℝ) (hyp : c = b * a - d) (hyp' : d = a * b) : c = 0 := by sorry -- Examples. example (a b c d e f : ℝ) (h : a * b = c * d) (h' : e = f) : a * (b * e) = c * (d * f) := by rw [h', ← mul_assoc, h, mul_assoc] section variable (a b c d e f g : ℝ) example (h : a * b = c * d) (h' : e = f) : a * (b * e) = c * (d * f) := by rw [h', ← mul_assoc, h, mul_assoc] end section variable (a b c : ℝ) #check a #check a + b #check (a : ℝ) #check mul_comm a b #check (mul_comm a b : a * b = b * a) #check mul_assoc c a b #check mul_comm a #check mul_comm #check @mul_comm end section variable (a b : ℝ) example : (a + b) * (a + b) = a * a + 2 * (a * b) + b * b := by rw [mul_add, add_mul, add_mul] rw [← add_assoc, add_assoc (a * a)] rw [mul_comm b a, ← two_mul] example : (a + b) * (a + b) = a * a + 2 * (a * b) + b * b := calc (a + b) * (a + b) = a * a + b * a + (a * b + b * b) := by rw [mul_add, add_mul, add_mul] _ = a * a + (b * a + a * b) + b * b := by rw [← add_assoc, add_assoc (a * a)] _ = a * a + 2 * (a * b) + b * b := by rw [mul_comm b a, ← two_mul] example : (a + b) * (a + b) = a * a + 2 * (a * b) + b * b := calc (a + b) * (a + b) = a * a + b * a + (a * b + b * b) := by sorry _ = a * a + (b * a + a * b) + b * b := by sorry _ = a * a + 2 * (a * b) + b * b := by sorry end -- Try these. For the second, use the theorems listed underneath. section variable (a b c d : ℝ) example : (a + b) * (c + d) = a * c + a * d + b * c + b * d := by sorry example (a b : ℝ) : (a + b) * (a - b) = a ^ 2 - b ^ 2 := by sorry #check pow_two a #check mul_sub a b c #check add_mul a b c #check add_sub a b c #check sub_sub a b c #check add_zero a end -- Examples. section variable (a b c d : ℝ) example (a b c d : ℝ) (hyp : c = d * a + b) (hyp' : b = a * d) : c = 2 * a * d := by rw [hyp'] at hyp rw [mul_comm d a] at hyp rw [← two_mul (a * d)] at hyp rw [← mul_assoc 2 a d] at hyp exact hyp example : c * b * a = b * (a * c) := by ring example : (a + b) * (a + b) = a * a + 2 * (a * b) + b * b := by ring example : (a + b) * (a - b) = a ^ 2 - b ^ 2 := by ring example (hyp : c = d * a + b) (hyp' : b = a * d) : c = 2 * a * d := by rw [hyp, hyp'] ring end example (a b c : ℕ) (h : a + b = c) : (a + b) * (a + b) = a * c + b * c := by nth_rw 2 [h] rw [add_mul]
-
-
-
@@ -0,0 +1,146 @@import Mathlib.Algebra.Ring.Defs import Mathlib.Data.Real.Basic import Mathlib.Tactic section variable (R : Type _) [Ring R] #check (add_assoc : ∀ a b c : R, a + b + c = a + (b + c)) #check (add_comm : ∀ a b : R, a + b = b + a) #check (zero_add : ∀ a : R, 0 + a = a) #check (add_left_neg : ∀ a : R, -a + a = 0) #check (mul_assoc : ∀ a b c : R, a * b * c = a * (b * c)) #check (mul_one : ∀ a : R, a * 1 = a) #check (one_mul : ∀ a : R, 1 * a = a) #check (mul_add : ∀ a b c : R, a * (b + c) = a * b + a * c) #check (add_mul : ∀ a b c : R, (a + b) * c = a * c + b * c) end section variable (R : Type _) [CommRing R] variable (a b c d : R) example : c * b * a = b * (a * c) := by ring example : (a + b) * (a + b) = a * a + 2 * (a * b) + b * b := by ring example : (a + b) * (a - b) = a ^ 2 - b ^ 2 := by ring example (hyp : c = d * a + b) (hyp' : b = a * d) : c = 2 * a * d := by rw [hyp, hyp'] ring end namespace MyRing variable {R : Type _} [Ring R] theorem add_zero (a : R) : a + 0 = a := by rw [add_comm, zero_add] theorem add_right_neg (a : R) : a + -a = 0 := by rw [add_comm, add_left_neg] #check @MyRing.add_zero #check @add_zero end MyRing namespace MyRing variable {R : Type _} [Ring R] theorem neg_add_cancel_left (a b : R) : -a + (a + b) = b := by rw [← add_assoc, add_left_neg, zero_add] -- Prove these: theorem add_neg_cancel_right (a b : R) : a + b + -b = a := by sorry theorem add_left_cancel {a b c : R} (h : a + b = a + c) : b = c := by sorry theorem add_right_cancel {a b c : R} (h : a + b = c + b) : a = c := by sorry theorem mul_zero (a : R) : a * 0 = 0 := by have h : a * 0 + a * 0 = a * 0 + 0 := by rw [← mul_add, add_zero, add_zero] rw [add_left_cancel h] theorem zero_mul (a : R) : 0 * a = 0 := by sorry theorem neg_eq_of_add_eq_zero {a b : R} (h : a + b = 0) : -a = b := by sorry theorem eq_neg_of_add_eq_zero {a b : R} (h : a + b = 0) : a = -b := by sorry theorem neg_zero : (-0 : R) = 0 := by apply neg_eq_of_add_eq_zero rw [add_zero] theorem neg_neg (a : R) : - -a = a := by sorry end MyRing -- Examples. section variable {R : Type _} [Ring R] example (a b : R) : a - b = a + -b := sub_eq_add_neg a b end example (a b : ℝ) : a - b = a + -b := rfl example (a b : ℝ) : a - b = a + -b := by rfl namespace MyRing variable {R : Type _} [Ring R] theorem self_sub (a : R) : a - a = 0 := sorry theorem one_add_one_eq_two : 1 + 1 = (2 : R) := by norm_num theorem two_mul (a : R) : 2 * a = a + a := sorry end MyRing section variable (A : Type _) [AddGroup A] #check (add_assoc : ∀ a b c : A, a + b + c = a + (b + c)) #check (zero_add : ∀ a : A, 0 + a = a) #check (add_left_neg : ∀ a : A, -a + a = 0) end section variable {G : Type _} [Group G] #check (mul_assoc : ∀ a b c : G, a * b * c = a * (b * c)) #check (one_mul : ∀ a : G, 1 * a = a) #check (mul_left_inv : ∀ a : G, a⁻¹ * a = 1) namespace MyGroup theorem mul_right_inv (a : G) : a * a⁻¹ = 1 := by sorry theorem mul_one (a : G) : a * 1 = a := by sorry theorem mul_inv_rev (a b : G) : (a * b)⁻¹ = b⁻¹ * a⁻¹ := by sorry end MyGroup end
-
-
-
@@ -0,0 +1,130 @@import Mathlib.Analysis.SpecialFunctions.Log.Basic import Mathlib.Tactic variable (a b c d e : ℝ) open Real #check (le_refl : ∀ a : ℝ, a ≤ a) #check (le_trans : a ≤ b → b ≤ c → a ≤ c) section variable (h : a ≤ b) (h' : b ≤ c) #check (le_refl : ∀ a : Real, a ≤ a) #check (le_refl a : a ≤ a) #check (le_trans : a ≤ b → b ≤ c → a ≤ c) #check (le_trans h : b ≤ c → a ≤ c) #check (le_trans h h' : a ≤ c) end example (x y z : ℝ) (h₀ : x ≤ y) (h₁ : y ≤ z) : x ≤ z := by apply le_trans · apply h₀ . apply h₁ example (x y z : ℝ) (h₀ : x ≤ y) (h₁ : y ≤ z) : x ≤ z := by apply le_trans h₀ apply h₁ example (x y z : ℝ) (h₀ : x ≤ y) (h₁ : y ≤ z) : x ≤ z := le_trans h₀ h₁ example (x : ℝ) : x ≤ x := by apply le_refl example (x : ℝ) : x ≤ x := le_refl x #check (le_refl : ∀ a, a ≤ a) #check (le_trans : a ≤ b → b ≤ c → a ≤ c) #check (lt_of_le_of_lt : a ≤ b → b < c → a < c) #check (lt_of_lt_of_le : a < b → b ≤ c → a < c) #check (lt_trans : a < b → b < c → a < c) -- Try this. example (h₀ : a ≤ b) (h₁ : b < c) (h₂ : c ≤ d) (h₃ : d < e) : a < e := by sorry example (h₀ : a ≤ b) (h₁ : b < c) (h₂ : c ≤ d) (h₃ : d < e) : a < e := by linarith section example (h : 2 * a ≤ 3 * b) (h' : 1 ≤ a) (h'' : d = 2) : d + a ≤ 5 * b := by linarith end example (h : 1 ≤ a) (h' : b ≤ c) : 2 + a + exp b ≤ 3 * a + exp c := by linarith [exp_le_exp.mpr h'] #check (exp_le_exp : exp a ≤ exp b ↔ a ≤ b) #check (exp_lt_exp : exp a < exp b ↔ a < b) #check (log_le_log : 0 < a → 0 < b → (log a ≤ log b ↔ a ≤ b)) #check (log_lt_log : 0 < a → a < b → log a < log b) #check (add_le_add : a ≤ b → c ≤ d → a + c ≤ b + d) #check (add_le_add_left : a ≤ b → ∀ c, c + a ≤ c + b) #check (add_le_add_right : a ≤ b → ∀ c, a + c ≤ b + c) #check (add_lt_add_of_le_of_lt : a ≤ b → c < d → a + c < b + d) #check (add_lt_add_of_lt_of_le : a < b → c ≤ d → a + c < b + d) #check (add_lt_add_left : a < b → ∀ c, c + a < c + b) #check (add_lt_add_right : a < b → ∀ c, a + c < b + c) #check (add_nonneg : 0 ≤ a → 0 ≤ b → 0 ≤ a + b) #check (add_pos : 0 < a → 0 < b → 0 < a + b) #check (add_pos_of_pos_of_nonneg : 0 < a → 0 ≤ b → 0 < a + b) #check (exp_pos : ∀ a, 0 < exp a) #check @add_le_add_left example (h : a ≤ b) : exp a ≤ exp b := by rw [exp_le_exp] exact h example (h₀ : a ≤ b) (h₁ : c < d) : a + exp c + e < b + exp d + e := by apply add_lt_add_of_lt_of_le · apply add_lt_add_of_le_of_lt h₀ apply exp_lt_exp.mpr h₁ apply le_refl example (h₀ : d ≤ e) : c + exp (a + d) ≤ c + exp (a + e) := by sorry example : (0 : ℝ) < 1 := by norm_num example (h : a ≤ b) : log (1 + exp a) ≤ log (1 + exp b) := by have h₀ : 0 < 1 + exp a := by sorry have h₁ : 0 < 1 + exp b := by sorry apply (log_le_log h₀ h₁).mpr sorry example : 0 ≤ a ^ 2 := by -- library_search exact sq_nonneg a example (h : a ≤ b) : c - exp b ≤ c - exp a := by sorry example : 2 * a * b ≤ a ^ 2 + b ^ 2 := by have h : 0 ≤ a ^ 2 - 2 * a * b + b ^ 2 calc a ^ 2 - 2 * a * b + b ^ 2 = (a - b) ^ 2 := by ring _ ≥ 0 := by apply pow_two_nonneg calc 2 * a * b = 2 * a * b + 0 := by ring _ ≤ 2 * a * b + (a ^ 2 - 2 * a * b + b ^ 2) := add_le_add (le_refl _) h _ = a ^ 2 + b ^ 2 := by ring example : 2 * a * b ≤ a ^ 2 + b ^ 2 := by have h : 0 ≤ a ^ 2 - 2 * a * b + b ^ 2 calc a ^ 2 - 2 * a * b + b ^ 2 = (a - b) ^ 2 := by ring _ ≥ 0 := by apply pow_two_nonneg linarith example : abs (a * b) ≤ (a ^ 2 + b ^ 2) / 2 := by sorry #check abs_le'.mpr
-
-
-
@@ -0,0 +1,90 @@import Mathlib.Data.Real.Basic namespace C02S04 section variable (a b c d : ℝ) #check (min_le_left a b : min a b ≤ a) #check (min_le_right a b : min a b ≤ b) #check (le_min : c ≤ a → c ≤ b → c ≤ min a b) example : min a b = min b a := by apply le_antisymm · show min a b ≤ min b a apply le_min · apply min_le_right apply min_le_left · show min b a ≤ min a b apply le_min · apply min_le_right apply min_le_left example : min a b = min b a := by have h : ∀ x y : ℝ, min x y ≤ min y x := by intro x y apply le_min apply min_le_right apply min_le_left apply le_antisymm apply h apply h example : min a b = min b a := by apply le_antisymm repeat apply le_min apply min_le_right apply min_le_left example : max a b = max b a := by sorry example : min (min a b) c = min a (min b c) := by sorry theorem aux : min a b + c ≤ min (a + c) (b + c) := by sorry example : min a b + c = min (a + c) (b + c) := by sorry #check (abs_add : ∀ a b : ℝ, abs (a + b) ≤ abs a + abs b) example : abs a - abs b ≤ abs (a - b) := sorry end section variable (w x y z : ℕ) example (h₀ : x ∣ y) (h₁ : y ∣ z) : x ∣ z := dvd_trans h₀ h₁ example : x ∣ y * x * z := by apply dvd_mul_of_dvd_left apply dvd_mul_left example : x ∣ x ^ 2 := by apply dvd_mul_left example (h : x ∣ w) : x ∣ y * (x * z) + x ^ 2 + w ^ 2 := by sorry end section variable (m n : ℕ) open Nat #check (gcd_zero_right n : gcd n 0 = n) #check (gcd_zero_left n : gcd 0 n = n) #check (lcm_zero_right n : lcm n 0 = 0) #check (lcm_zero_left n : lcm 0 n = 0) example : gcd m n = gcd n m := by sorry end
-
-
-
@@ -0,0 +1,109 @@import Mathlib.Topology.MetricSpace.Basic section variable {α : Type _} [PartialOrder α] variable (x y z : α) #check x ≤ y #check (le_refl x : x ≤ x) #check (le_trans : x ≤ y → y ≤ z → x ≤ z) #check x < y #check (lt_irrefl x : ¬x < x) #check (lt_trans : x < y → y < z → x < z) #check (lt_of_le_of_lt : x ≤ y → y < z → x < z) #check (lt_of_lt_of_le : x < y → y ≤ z → x < z) example : x < y ↔ x ≤ y ∧ x ≠ y := lt_iff_le_and_ne end section variable {α : Type _} [Lattice α] variable (x y z : α) #check x ⊓ y #check (inf_le_left : x ⊓ y ≤ x) #check (inf_le_right : x ⊓ y ≤ y) #check (le_inf : z ≤ x → z ≤ y → z ≤ x ⊓ y) #check x ⊔ y #check (le_sup_left : x ≤ x ⊔ y) #check (le_sup_right : y ≤ x ⊔ y) #check (sup_le : x ≤ z → y ≤ z → x ⊔ y ≤ z) example : x ⊓ y = y ⊓ x := by sorry example : x ⊓ y ⊓ z = x ⊓ (y ⊓ z) := by sorry example : x ⊔ y = y ⊔ x := by sorry example : x ⊔ y ⊔ z = x ⊔ (y ⊔ z) := by sorry theorem absorb1 : x ⊓ (x ⊔ y) = x := by sorry theorem absorb2 : x ⊔ x ⊓ y = x := by sorry end section variable {α : Type _} [DistribLattice α] variable (x y z : α) #check (inf_sup_left : x ⊓ (y ⊔ z) = x ⊓ y ⊔ x ⊓ z) #check (inf_sup_right : (x ⊔ y) ⊓ z = x ⊓ z ⊔ y ⊓ z) #check (sup_inf_left : x ⊔ y ⊓ z = (x ⊔ y) ⊓ (x ⊔ z)) #check (sup_inf_right : x ⊓ y ⊔ z = (x ⊔ z) ⊓ (y ⊔ z)) end section variable {α : Type _} [Lattice α] variable (a b c : α) example (h : ∀ x y z : α, x ⊓ (y ⊔ z) = x ⊓ y ⊔ x ⊓ z) : a ⊔ b ⊓ c = (a ⊔ b) ⊓ (a ⊔ c) := by sorry example (h : ∀ x y z : α, x ⊔ y ⊓ z = (x ⊔ y) ⊓ (x ⊔ z)) : a ⊓ (b ⊔ c) = a ⊓ b ⊔ a ⊓ c := by sorry end section variable {R : Type _} [StrictOrderedRing R] variable (a b c : R) #check (add_le_add_left : a ≤ b → ∀ c, c + a ≤ c + b) #check (mul_pos : 0 < a → 0 < b → 0 < a * b) #check (mul_nonneg : 0 ≤ a → 0 ≤ b → 0 ≤ a * b) example : a ≤ b → 0 ≤ b - a := by sorry example : 0 ≤ b - a → a ≤ b := by sorry example (h : a ≤ b) (h' : 0 ≤ c) : a * c ≤ b * c := by sorry end section variable {X : Type _} [MetricSpace X] variable (x y z : X) #check (dist_self x : dist x x = 0) #check (dist_comm x y : dist x y = dist y x) #check (dist_triangle x y z : dist x z ≤ dist x y + dist y z) example (x y : X) : 0 ≤ dist x y := by sorry end
-
-
-
@@ -0,0 +1,33 @@import Mathlib.Data.Real.Basic import Mathlib.Data.Real.Basic example (a b c : ℝ) : c * b * a = b * (a * c) := by rw [mul_comm c b] rw [mul_assoc b c a] rw [mul_comm c a] example (a b c : ℝ) : a * (b * c) = b * (a * c) := by rw [← mul_assoc a b c] rw [mul_comm a b] rw [mul_assoc b a c] example (a b c : ℝ) : a * (b * c) = b * (c * a) := by rw [mul_comm] rw [mul_assoc] example (a b c : ℝ) : a * (b * c) = b * (a * c) := by rw [← mul_assoc] rw [mul_comm a] rw [mul_assoc] example (a b c d e f : ℝ) (h : b * c = e * f) : a * b * c * d = a * e * f * d := by rw [mul_assoc a] rw [h] rw [← mul_assoc] example (a b c d : ℝ) (hyp : c = b * a - d) (hyp' : d = a * b) : c = 0 := by rw [hyp] rw [hyp'] rw [mul_comm] rw [sub_self]
-
-
-
@@ -0,0 +1,73 @@import Mathlib.Algebra.Ring.Defs import Mathlib.Data.Real.Basic import Mathlib.Tactic namespace MyRing variable {R : Type _} [Ring R] theorem add_neg_cancel_right (a b : R) : a + b + -b = a := by rw [add_assoc, add_right_neg, add_zero] theorem add_left_cancel {a b c : R} (h : a + b = a + c) : b = c := by rw [← neg_add_cancel_left a b, h, neg_add_cancel_left] theorem add_right_cancel {a b c : R} (h : a + b = c + b) : a = c := by rw [← add_neg_cancel_right a b, h, add_neg_cancel_right] theorem zero_mul (a : R) : 0 * a = 0 := by have h : 0 * a + 0 * a = 0 * a + 0 := by rw [← add_mul, add_zero, add_zero] rw [add_left_cancel h] theorem neg_eq_of_add_eq_zero {a b : R} (h : a + b = 0) : -a = b := by rw [← neg_add_cancel_left a b, h, add_zero] theorem eq_neg_of_add_eq_zero {a b : R} (h : a + b = 0) : a = -b := by symm apply neg_eq_of_add_eq_zero rw [add_comm, h] theorem neg_zero : (-0 : R) = 0 := by apply neg_eq_of_add_eq_zero rw [add_zero] theorem neg_neg (a : R) : - -a = a := by apply neg_eq_of_add_eq_zero rw [add_left_neg] end MyRing namespace MyRing variable {R : Type _} [Ring R] theorem self_sub (a : R) : a - a = 0 := by rw [sub_eq_add_neg, add_right_neg] theorem one_add_one_eq_two : 1 + 1 = (2 : R) := by norm_num theorem two_mul (a : R) : 2 * a = a + a := by rw [← one_add_one_eq_two, add_mul, one_mul] end MyRing section variable {G : Type _} [Group G] namespace MyGroup theorem mul_right_inv (a : G) : a * a⁻¹ = 1 := by have h : (a * a⁻¹)⁻¹ * (a * a⁻¹ * (a * a⁻¹)) = 1 := by rw [mul_assoc, ← mul_assoc a⁻¹ a, mul_left_inv, one_mul, mul_left_inv] rw [← h, ← mul_assoc, mul_left_inv, one_mul] theorem mul_one (a : G) : a * 1 = a := by rw [← mul_left_inv a, ← mul_assoc, mul_right_inv, one_mul] theorem mul_inv_rev (a b : G) : (a * b)⁻¹ = b⁻¹ * a⁻¹ := by rw [← one_mul (b⁻¹ * a⁻¹), ← mul_left_inv (a * b), mul_assoc, mul_assoc, ← mul_assoc b b⁻¹, mul_right_inv, one_mul, mul_right_inv, mul_one] end MyGroup end
-
-
-
@@ -0,0 +1,61 @@import Mathlib.Analysis.SpecialFunctions.Log.Basic import Mathlib.Tactic variable (a b c d e : ℝ) open Real example (h₀ : a ≤ b) (h₁ : b < c) (h₂ : c ≤ d) (h₃ : d < e) : a < e := by apply lt_of_le_of_lt h₀ apply lt_trans h₁ exact lt_of_le_of_lt h₂ h₃ example (h₀ : d ≤ e) : c + exp (a + d) ≤ c + exp (a + e) := by apply add_le_add_left rw [exp_le_exp] apply add_le_add_left h₀ -- an alternative using `linarith`. example (h₀ : d ≤ e) : c + exp (a + d) ≤ c + exp (a + e) := by have : exp (a + d) ≤ exp (a + e) := by rw [exp_le_exp] linarith linarith [this] example (h : a ≤ b) : log (1 + exp a) ≤ log (1 + exp b) := by have h₀ : 0 < 1 + exp a := by linarith [exp_pos a] have h₁ : 0 < 1 + exp b := by linarith [exp_pos b] apply (log_le_log h₀ h₁).mpr apply add_le_add_left (exp_le_exp.mpr h) -- SOLUTION. example (h : a ≤ b) : c - exp b ≤ c - exp a := by apply sub_le_sub_left exact exp_le_exp.mpr h -- alternatively: example (h : a ≤ b) : c - exp b ≤ c - exp a := by linarith [exp_le_exp.mpr h] theorem fact1 : a * b * 2 ≤ a ^ 2 + b ^ 2 := by have h : 0 ≤ a ^ 2 - 2 * a * b + b ^ 2 calc a ^ 2 - 2 * a * b + b ^ 2 = (a - b) ^ 2 := by ring _ ≥ 0 := by apply pow_two_nonneg linarith theorem fact2 : -(a * b) * 2 ≤ a ^ 2 + b ^ 2 := by have h : 0 ≤ a ^ 2 + 2 * a * b + b ^ 2 calc a ^ 2 + 2 * a * b + b ^ 2 = (a + b) ^ 2 := by ring _ ≥ 0 := by apply pow_two_nonneg linarith example : abs (a * b) ≤ (a ^ 2 + b ^ 2) / 2 := by have h : (0 : ℝ) < 2 := by norm_num apply abs_le'.mpr constructor · rw [le_div_iff h] apply fact1 rw [le_div_iff h] apply fact2
-
-
-
@@ -0,0 +1,116 @@import Mathlib.Data.Real.Basic namespace C02S04 section variable (a b c d : ℝ) #check (min_le_left a b : min a b ≤ a) #check (min_le_right a b : min a b ≤ b) #check (le_min : c ≤ a → c ≤ b → c ≤ min a b) example : max a b = max b a := by apply le_antisymm repeat' apply max_le apply le_max_right apply le_max_left example : min (min a b) c = min a (min b c) := by apply le_antisymm · apply le_min · apply le_trans apply min_le_left apply min_le_left apply le_min · apply le_trans apply min_le_left apply min_le_right apply min_le_right apply le_min · apply le_min · apply min_le_left apply le_trans apply min_le_right apply min_le_left apply le_trans apply min_le_right apply min_le_right theorem aux : min a b + c ≤ min (a + c) (b + c) := by apply le_min · apply add_le_add_right apply min_le_left apply add_le_add_right apply min_le_right example : min a b + c = min (a + c) (b + c) := by apply le_antisymm · apply aux have h : min (a + c) (b + c) = min (a + c) (b + c) - c + c := by rw [sub_add_cancel] rw [h] apply add_le_add_right rw [sub_eq_add_neg] apply le_trans apply aux rw [add_neg_cancel_right, add_neg_cancel_right] example : abs a - abs b ≤ abs (a - b) := calc abs a - abs b = abs (a - b + b) - abs b := by rw [sub_add_cancel] _ ≤ abs (a - b) + abs b - abs b := by apply sub_le_sub_right apply abs_add _ ≤ abs (a - b) := by rw [add_sub_cancel] -- alternatively example : abs a - abs b ≤ abs (a - b) := by have h := abs_add (a - b) b rw [sub_add_cancel] at h linarith end section variable (w x y z : ℕ) example (h₀ : x ∣ y) (h₁ : y ∣ z) : x ∣ z := dvd_trans h₀ h₁ example : x ∣ y * x * z := by apply dvd_mul_of_dvd_left apply dvd_mul_left example : x ∣ x ^ 2 := by apply dvd_mul_left example (h : x ∣ w) : x ∣ y * (x * z) + x ^ 2 + w ^ 2 := by apply dvd_add · apply dvd_add · apply dvd_mul_of_dvd_right apply dvd_mul_right apply dvd_mul_left rw [pow_two] apply dvd_mul_of_dvd_right exact h end section variable (m n : ℕ) open Nat #check (gcd_zero_right n : gcd n 0 = n) #check (gcd_zero_left n : gcd 0 n = n) #check (lcm_zero_right n : lcm n 0 = 0) #check (lcm_zero_left n : lcm 0 n = 0) example : gcd m n = gcd n m := by apply _root_.dvd_antisymm repeat' apply dvd_gcd apply gcd_dvd_right apply gcd_dvd_left end
-
-
-
@@ -0,0 +1,135 @@import Mathlib.Topology.MetricSpace.Basic section variable {α : Type _} [Lattice α] variable (x y z : α) example : x ⊓ y = y ⊓ x := by apply le_antisymm repeat' apply le_inf · apply inf_le_right apply inf_le_left example : x ⊓ y ⊓ z = x ⊓ (y ⊓ z) := by apply le_antisymm · apply le_inf · apply le_trans apply inf_le_left apply inf_le_left apply le_inf · apply le_trans apply inf_le_left apply inf_le_right apply inf_le_right apply le_inf · apply le_inf · apply inf_le_left apply le_trans apply inf_le_right apply inf_le_left apply le_trans apply inf_le_right apply inf_le_right example : x ⊔ y = y ⊔ x := by apply le_antisymm repeat' apply sup_le · apply le_sup_right apply le_sup_left example : x ⊔ y ⊔ z = x ⊔ (y ⊔ z) := by apply le_antisymm · apply sup_le · apply sup_le apply le_sup_left · apply le_trans apply @le_sup_left _ _ y z apply le_sup_right apply le_trans apply @le_sup_right _ _ y z apply le_sup_right apply sup_le · apply le_trans apply @le_sup_left _ _ x y apply le_sup_left apply sup_le · apply le_trans apply @le_sup_right _ _ x y apply le_sup_left apply le_sup_right theorem absorb1 : x ⊓ (x ⊔ y) = x := by apply le_antisymm · apply inf_le_left apply le_inf · apply le_refl apply le_sup_left theorem absorb2 : x ⊔ x ⊓ y = x := by apply le_antisymm · apply sup_le · apply le_refl apply inf_le_left apply le_sup_left end section variable {α : Type _} [DistribLattice α] variable (x y z : α) #check (inf_sup_left : x ⊓ (y ⊔ z) = x ⊓ y ⊔ x ⊓ z) #check (inf_sup_right : (x ⊔ y) ⊓ z = x ⊓ z ⊔ y ⊓ z) #check (sup_inf_left : x ⊔ y ⊓ z = (x ⊔ y) ⊓ (x ⊔ z)) #check (sup_inf_right : x ⊓ y ⊔ z = (x ⊔ z) ⊓ (y ⊔ z)) end section variable {α : Type _} [Lattice α] variable (a b c : α) example (h : ∀ x y z : α, x ⊓ (y ⊔ z) = x ⊓ y ⊔ x ⊓ z) : a ⊔ b ⊓ c = (a ⊔ b) ⊓ (a ⊔ c) := by rw [h, @inf_comm _ _ (a ⊔ b), absorb1, @inf_comm _ _ (a ⊔ b), h, ← sup_assoc, @inf_comm _ _ c a, absorb2, inf_comm] example (h : ∀ x y z : α, x ⊔ y ⊓ z = (x ⊔ y) ⊓ (x ⊔ z)) : a ⊓ (b ⊔ c) = a ⊓ b ⊔ a ⊓ c := by rw [h, @sup_comm _ _ (a ⊓ b), absorb2, @sup_comm _ _ (a ⊓ b), h, ← inf_assoc, @sup_comm _ _ c a, absorb1, sup_comm] end section variable {R : Type _} [StrictOrderedRing R] variable (a b c : R) theorem aux1 : a ≤ b → 0 ≤ b - a := by intro h rw [← sub_self a, sub_eq_add_neg, sub_eq_add_neg, add_comm, add_comm b] apply add_le_add_left h theorem aux2 : 0 ≤ b - a → a ≤ b := by intro h rw [← add_zero a, ← sub_add_cancel b a, add_comm (b - a)] apply add_le_add_left h example (h : a ≤ b) (h' : 0 ≤ c) : a * c ≤ b * c := by have h1 : 0 ≤ (b - a) * c := mul_nonneg (aux1 _ _ h) h' rw [sub_mul] at h1 exact aux2 _ _ h1 end section variable {X : Type _} [MetricSpace X] variable (x y z : X) example (x y : X) : 0 ≤ dist x y :=by have : 0 ≤ dist x y + dist y x := by rw [← dist_self x] apply dist_triangle linarith [dist_comm x y] end
-
-
-
@@ -0,0 +1,178 @@import Mathlib.Data.Real.Basic namespace C03S01 #check ∀ x : ℝ, 0 ≤ x → abs x = x #check ∀ x y ε : ℝ, 0 < ε → ε ≤ 1 → abs x < ε → abs y < ε → abs (x * y) < ε theorem my_lemma : ∀ x y ε : ℝ, 0 < ε → ε ≤ 1 → abs x < ε → abs y < ε → abs (x * y) < ε := sorry section variable (a b δ : ℝ) variable (h₀ : 0 < δ) (h₁ : δ ≤ 1) variable (ha : abs a < δ) (hb : abs b < δ) #check my_lemma a b δ #check my_lemma a b δ h₀ h₁ #check my_lemma a b δ h₀ h₁ ha hb end theorem my_lemma2 : ∀ {x y ε : ℝ}, 0 < ε → ε ≤ 1 → abs x < ε → abs y < ε → abs (x * y) < ε := sorry section variable (a b δ : ℝ) variable (h₀ : 0 < δ) (h₁ : δ ≤ 1) variable (ha : abs a < δ) (hb : abs b < δ) #check my_lemma2 h₀ h₁ ha hb end theorem my_lemma3 : ∀ {x y ε : ℝ}, 0 < ε → ε ≤ 1 → abs x < ε → abs y < ε → abs (x * y) < ε := by intro x y ε epos ele1 xlt ylt sorry theorem my_lemma4 : ∀ {x y ε : ℝ}, 0 < ε → ε ≤ 1 → abs x < ε → abs y < ε → abs (x * y) < ε := by intro x y ε epos ele1 xlt ylt calc abs (x * y) = abs x * abs y := sorry _ ≤ abs x * ε := sorry _ < 1 * ε := sorry _ = ε := sorry def FnUb (f : ℝ → ℝ) (a : ℝ) : Prop := ∀ x, f x ≤ a def FnLb (f : ℝ → ℝ) (a : ℝ) : Prop := ∀ x, a ≤ f x section variable (f g : ℝ → ℝ) (a b : ℝ) example (hfa : FnUb f a) (hgb : FnUb g b) : FnUb (fun x ↦ f x + g x) (a + b) := by intro x dsimp apply add_le_add apply hfa apply hgb example (hfa : FnLb f a) (hgb : FnLb g b) : FnLb (fun x => f x + g x) (a + b) := sorry example (nnf : FnLb f 0) (nng : FnLb g 0) : FnLb (fun x => f x * g x) 0 := sorry example (hfa : FnUb f a) (hfb : FnUb g b) (nng : FnLb g 0) (nna : 0 ≤ a) : FnUb (fun x => f x * g x) (a * b) := sorry end section variable {α : Type _} {R : Type _} [OrderedCancelAddCommMonoid R] #check @add_le_add def FnUb' (f : α → R) (a : R) : Prop := ∀ x, f x ≤ a theorem fnUb_add {f g : α → R} {a b : R} (hfa : FnUb' f a) (hgb : FnUb' g b) : FnUb' (fun x => f x + g x) (a + b) := fun x => add_le_add (hfa x) (hgb x) end example (f : ℝ → ℝ) (h : Monotone f) : ∀ {a b}, a ≤ b → f a ≤ f b := @h section variable (f g : ℝ → ℝ) example (mf : Monotone f) (mg : Monotone g) : Monotone fun x => f x + g x := by intro a b aleb apply add_le_add apply mf aleb apply mg aleb example (mf : Monotone f) (mg : Monotone g) : Monotone fun x => f x + g x := fun a b aleb => add_le_add (mf aleb) (mg aleb) example {c : ℝ} (mf : Monotone f) (nnc : 0 ≤ c) : Monotone fun x => c * f x := sorry example (mf : Monotone f) (mg : Monotone g) : Monotone fun x => f (g x) := sorry def FnEven (f : ℝ → ℝ) : Prop := ∀ x, f x = f (-x) def FnOdd (f : ℝ → ℝ) : Prop := ∀ x, f x = -f (-x) example (ef : FnEven f) (eg : FnEven g) : FnEven fun x => f x + g x := by intro x calc (fun x => f x + g x) x = f x + g x := rfl _ = f (-x) + g (-x) := by rw [ef, eg] example (of : FnOdd f) (og : FnOdd g) : FnEven fun x => f x * g x := by sorry example (ef : FnEven f) (og : FnOdd g) : FnOdd fun x => f x * g x := by sorry example (ef : FnEven f) (og : FnOdd g) : FnEven fun x => f (g x) := by sorry end section variable {α : Type _} (r s t : Set α) example : s ⊆ s := by intro x xs exact xs theorem Subset.refl : s ⊆ s := fun x xs => xs theorem Subset.trans : r ⊆ s → s ⊆ t → r ⊆ t := by sorry end section variable {α : Type _} [PartialOrder α] variable (s : Set α) (a b : α) def SetUb (s : Set α) (a : α) := ∀ x, x ∈ s → x ≤ a example (h : SetUb s a) (h' : a ≤ b) : SetUb s b := sorry end section open Function example (c : ℝ) : Injective fun x => x + c := by intro x₁ x₂ h' exact (add_left_inj c).mp h' example {c : ℝ} (h : c ≠ 0) : Injective fun x => c * x := by sorry variable {α : Type _} {β : Type _} {γ : Type _} variable {g : β → γ} {f : α → β} example (injg : Injective g) (injf : Injective f) : Injective fun x => g (f x) := by sorry end
-
-
-
@@ -0,0 +1,131 @@import Mathlib.Data.Real.Basic namespace C03S02 example : ∃ x : ℝ, 2 < x ∧ x < 3 := by use 5 / 2 norm_num example : ∃ x : ℝ, 2 < x ∧ x < 3 := have h : 2 < (5 : ℝ) / 2 ∧ (5 : ℝ) / 2 < 3 := by norm_num ⟨5 / 2, h⟩ example : ∃ x : ℝ, 2 < x ∧ x < 3 := ⟨5 / 2, by norm_num⟩ def FnUb (f : ℝ → ℝ) (a : ℝ) : Prop := ∀ x, f x ≤ a def FnLb (f : ℝ → ℝ) (a : ℝ) : Prop := ∀ x, a ≤ f x def FnHasUb (f : ℝ → ℝ) := ∃ a, FnUb f a def FnHasLb (f : ℝ → ℝ) := ∃ a, FnLb f a theorem fnUb_add {f g : ℝ → ℝ} {a b : ℝ} (hfa : FnUb f a) (hgb : FnUb g b) : FnUb (fun x => f x + g x) (a + b) := fun x => add_le_add (hfa x) (hgb x) section variable {f g : ℝ → ℝ} example (ubf : FnHasUb f) (ubg : FnHasUb g) : FnHasUb fun x => f x + g x := by cases' ubf with a ubfa cases' ubg with b ubgb use a + b apply fnUb_add ubfa ubgb example (lbf : FnHasLb f) (lbg : FnHasLb g) : FnHasLb fun x => f x + g x := by sorry example {c : ℝ} (ubf : FnHasUb f) (h : c ≥ 0) : FnHasUb fun x => c * f x := by sorry example (ubf : FnHasUb f) (ubg : FnHasUb g) : FnHasUb fun x => f x + g x := by rcases ubf with ⟨a, ubfa⟩ rcases ubg with ⟨b, ubgb⟩ exact ⟨a + b, fnUb_add ubfa ubgb⟩ example : FnHasUb f → FnHasUb g → FnHasUb fun x => f x + g x := by rintro ⟨a, ubfa⟩ ⟨b, ubgb⟩ exact ⟨a + b, fnUb_add ubfa ubgb⟩ example : FnHasUb f → FnHasUb g → FnHasUb fun x => f x + g x := fun ⟨a, ubfa⟩ ⟨b, ubgb⟩ => ⟨a + b, fnUb_add ubfa ubgb⟩ end section variable {α : Type _} [CommRing α] def SumOfSquares (x : α) := ∃ a b, x = a ^ 2 + b ^ 2 theorem sumOfSquares_mul {x y : α} (sosx : SumOfSquares x) (sosy : SumOfSquares y) : SumOfSquares (x * y) := by rcases sosx with ⟨a, b, xeq⟩ rcases sosy with ⟨c, d, yeq⟩ rw [xeq, yeq] use a * c - b * d, a * d + b * c ring theorem sumOfSquares_mul' {x y : α} (sosx : SumOfSquares x) (sosy : SumOfSquares y) : SumOfSquares (x * y) := by rcases sosx with ⟨a, b, rfl⟩ rcases sosy with ⟨c, d, rfl⟩ use a * c - b * d, a * d + b * c ring end section variable {a b c : ℕ} example (divab : a ∣ b) (divbc : b ∣ c) : a ∣ c := by cases' divab with d beq cases' divbc with e ceq rw [ceq, beq] use d * e; ring example (divab : a ∣ b) (divac : a ∣ c) : a ∣ b + c := by sorry end section open Function example {c : ℝ} : Surjective fun x => x + c := by intro x use x - c dsimp; ring example {c : ℝ} (h : c ≠ 0) : Surjective fun x => c * x := by sorry example (x y : ℝ) (h : x - y ≠ 0) : (x ^ 2 - y ^ 2) / (x - y) = x + y := by field_simp [h] ring example {f : ℝ → ℝ} (h : Surjective f) : ∃ x, f x ^ 2 = 4 := by cases' h 2 with x hx use x rw [hx] norm_num end section open Function variable {α : Type _} {β : Type _} {γ : Type _} variable {g : β → γ} {f : α → β} example (surjg : Surjective g) (surjf : Surjective f) : Surjective fun x => g (f x) := by sorry end
-
-
-
@@ -0,0 +1,137 @@import Mathlib.Data.Real.Basic namespace C03S03 section variable (a b : ℝ) example (h : a < b) : ¬b < a := by intro h' have : a < a := lt_trans h h' apply lt_irrefl a this def FnUb (f : ℝ → ℝ) (a : ℝ) : Prop := ∀ x, f x ≤ a def FnLb (f : ℝ → ℝ) (a : ℝ) : Prop := ∀ x, a ≤ f x def FnHasUb (f : ℝ → ℝ) := ∃ a, FnUb f a def FnHasLb (f : ℝ → ℝ) := ∃ a, FnLb f a variable (f : ℝ → ℝ) example (h : ∀ a, ∃ x, f x > a) : ¬FnHasUb f := by intro fnub cases' fnub with a fnuba cases' h a with x hx have : f x ≤ a := fnuba x linarith example (h : ∀ a, ∃ x, f x < a) : ¬FnHasLb f := sorry example : ¬FnHasUb fun x => x := sorry #check (not_le_of_gt : a > b → ¬a ≤ b) #check (not_lt_of_ge : a ≥ b → ¬a < b) #check (lt_of_not_ge : ¬a ≥ b → a < b) #check (le_of_not_gt : ¬a > b → a ≤ b) example (h : Monotone f) (h' : f a < f b) : a < b := by sorry example (h : a ≤ b) (h' : f b < f a) : ¬Monotone f := by sorry example : ¬∀ {f : ℝ → ℝ}, Monotone f → ∀ {a b}, f a ≤ f b → a ≤ b := by intro h let f := fun x : ℝ => (0 : ℝ) have monof : Monotone f := by sorry have h' : f 1 ≤ f 0 := le_refl _ sorry example (x : ℝ) (h : ∀ ε > 0, x < ε) : x ≤ 0 := by sorry end section variable {α : Type _} (P : α → Prop) (Q : Prop) example (h : ¬∃ x, P x) : ∀ x, ¬P x := by sorry example (h : ∀ x, ¬P x) : ¬∃ x, P x := by sorry example (h : ¬∀ x, P x) : ∃ x, ¬P x := by sorry example (h : ∃ x, ¬P x) : ¬∀ x, P x := by sorry example (h : ¬∀ x, P x) : ∃ x, ¬P x := by by_contra h' apply h intro x show P x by_contra h'' exact h' ⟨x, h''⟩ example (h : ¬¬Q) : Q := by sorry example (h : Q) : ¬¬Q := by sorry end section variable (f : ℝ → ℝ) example (h : ¬FnHasUb f) : ∀ a, ∃ x, f x > a := by sorry example (h : ¬∀ a, ∃ x, f x > a) : FnHasUb f := by push_neg at h exact h example (h : ¬FnHasUb f) : ∀ a, ∃ x, f x > a := by simp only [FnHasUb, FnUb] at h push_neg at h exact h example (h : ¬Monotone f) : ∃ x y, x ≤ y ∧ f y < f x := by sorry example (h : ¬FnHasUb f) : ∀ a, ∃ x, f x > a := by contrapose! h exact h example (x : ℝ) (h : ∀ ε > 0, x ≤ ε) : x ≤ 0 := by contrapose! h use x / 2 constructor <;> linarith end section variable (a : ℕ) example (h : 0 < 0) : a > 37 := by exfalso apply lt_irrefl 0 h example (h : 0 < 0) : a > 37 := absurd h (lt_irrefl 0) example (h : 0 < 0) : a > 37 := by have h' : ¬0 < 0 := lt_irrefl 0 contradiction end
-
-
-
@@ -0,0 +1,135 @@import Mathlib.Data.Real.Basic import Mathlib.Data.Nat.Prime import Mathlib.Tactic.NormNum namespace C03S04 example {x y : ℝ} (h₀ : x ≤ y) (h₁ : ¬y ≤ x) : x ≤ y ∧ x ≠ y := by constructor · assumption intro h apply h₁ rw [h] example {x y : ℝ} (h₀ : x ≤ y) (h₁ : ¬y ≤ x) : x ≤ y ∧ x ≠ y := ⟨h₀, fun h => h₁ (by rw [h])⟩ example {x y : ℝ} (h₀ : x ≤ y) (h₁ : ¬y ≤ x) : x ≤ y ∧ x ≠ y := have h : x ≠ y := by contrapose! h₁ rw [h₁] ⟨h₀, h⟩ example {x y : ℝ} (h : x ≤ y ∧ x ≠ y) : ¬y ≤ x := by cases' h with h₀ h₁ contrapose! h₁ exact le_antisymm h₀ h₁ example {x y : ℝ} : x ≤ y ∧ x ≠ y → ¬y ≤ x := by rintro ⟨h₀, h₁⟩ h' exact h₁ (le_antisymm h₀ h') example {x y : ℝ} : x ≤ y ∧ x ≠ y → ¬y ≤ x := fun ⟨h₀, h₁⟩ h' => h₁ (le_antisymm h₀ h') example {x y : ℝ} (h : x ≤ y ∧ x ≠ y) : ¬y ≤ x := by intro h' apply h.right exact le_antisymm h.left h' example {x y : ℝ} (h : x ≤ y ∧ x ≠ y) : ¬y ≤ x := fun h' => h.right (le_antisymm h.left h') example {m n : ℕ} (h : m ∣ n ∧ m ≠ n) : m ∣ n ∧ ¬n ∣ m := sorry example : ∃ x : ℝ, 2 < x ∧ x < 4 := ⟨5 / 2, by norm_num, by norm_num⟩ example (x y : ℝ) : (∃ z : ℝ, x < z ∧ z < y) → x < y := by rintro ⟨z, xltz, zlty⟩ exact lt_trans xltz zlty example (x y : ℝ) : (∃ z : ℝ, x < z ∧ z < y) → x < y := fun ⟨z, xltz, zlty⟩ => lt_trans xltz zlty example : ∃ x : ℝ, 2 < x ∧ x < 4 := by use 5 / 2 constructor <;> norm_num example : ∃ m n : ℕ, 4 < m ∧ m < n ∧ n < 10 ∧ Nat.Prime m ∧ Nat.Prime n := by use 5 use 7 norm_num sorry example {x y : ℝ} : x ≤ y ∧ x ≠ y → x ≤ y ∧ ¬y ≤ x := by rintro ⟨h₀, h₁⟩ use h₀ exact fun h' => h₁ (le_antisymm h₀ h') example {x y : ℝ} (h : x ≤ y) : ¬y ≤ x ↔ x ≠ y := by constructor · contrapose! rintro rfl rfl contrapose! exact le_antisymm h example {x y : ℝ} (h : x ≤ y) : ¬y ≤ x ↔ x ≠ y := ⟨fun h₀ h₁ => h₀ (by rw [h₁]), fun h₀ h₁ => h₀ (le_antisymm h h₁)⟩ example {x y : ℝ} : x ≤ y ∧ ¬y ≤ x ↔ x ≤ y ∧ x ≠ y := sorry theorem aux {x y : ℝ} (h : x ^ 2 + y ^ 2 = 0) : x = 0 := have h' : x ^ 2 = 0 := by sorry pow_eq_zero h' example (x y : ℝ) : x ^ 2 + y ^ 2 = 0 ↔ x = 0 ∧ y = 0 := sorry section example (x : ℝ) : abs (x + 3) < 5 → -8 < x ∧ x < 2 := by rw [abs_lt] intro h constructor <;> linarith example : 3 ∣ Nat.gcd 6 15 := by rw [Nat.dvd_gcd_iff] constructor <;> norm_num end theorem not_monotone_iff {f : ℝ → ℝ} : ¬Monotone f ↔ ∃ x y, x ≤ y ∧ f x > f y := by rw [Monotone] push_neg rfl example : ¬Monotone fun x : ℝ => -x := by sorry section variable {α : Type _} [PartialOrder α] variable (a b : α) example : a < b ↔ a ≤ b ∧ a ≠ b := by rw [lt_iff_le_not_le] sorry end section variable {α : Type _} [Preorder α] variable (a b c : α) example : ¬a < a := by rw [lt_iff_le_not_le] sorry example : a < b → b < c → a < c := by simp only [lt_iff_le_not_le] sorry end
-
-
-
@@ -0,0 +1,101 @@import Mathlib.Data.Real.Basic namespace C03S05 section variable {x y : ℝ} example (h : y > x ^ 2) : y > 0 ∨ y < -1 := by left linarith [pow_two_nonneg x] example (h : -y > x ^ 2 + 1) : y > 0 ∨ y < -1 := by right linarith [pow_two_nonneg x] example (h : y > 0) : y > 0 ∨ y < -1 := Or.inl h example (h : y < -1) : y > 0 ∨ y < -1 := Or.inr h example : x < abs y → x < y ∨ x < -y := by cases' le_or_gt 0 y with h h · rw [abs_of_nonneg h] intro h left exact h rw [abs_of_neg h] intro h; right; exact h namespace MyAbs theorem le_abs_self (x : ℝ) : x ≤ abs x := by sorry theorem neg_le_abs_self (x : ℝ) : -x ≤ abs x := by sorry theorem abs_add (x y : ℝ) : abs (x + y) ≤ abs x + abs y := by sorry theorem lt_abs : x < abs y ↔ x < y ∨ x < -y := by sorry theorem abs_lt : abs x < y ↔ -y < x ∧ x < y := by sorry end MyAbs end example {x : ℝ} (h : x ≠ 0) : x < 0 ∨ x > 0 := by rcases lt_trichotomy x 0 with (xlt | xeq | xgt) · left exact xlt · contradiction right; exact xgt example {m n k : ℕ} (h : m ∣ n ∨ m ∣ k) : m ∣ n * k := by rcases h with (⟨a, rfl⟩ | ⟨b, rfl⟩) · rw [mul_assoc] apply dvd_mul_right rw [mul_comm, mul_assoc] apply dvd_mul_right example {z : ℝ} (h : ∃ x y, z = x ^ 2 + y ^ 2 ∨ z = x ^ 2 + y ^ 2 + 1) : z ≥ 0 := by sorry example {x : ℝ} (h : x ^ 2 = 1) : x = 1 ∨ x = -1 := by sorry example {x y : ℝ} (h : x ^ 2 = y ^ 2) : x = y ∨ x = -y := by sorry section variable {R : Type _} [CommRing R] [IsDomain R] variable (x y : R) example (h : x ^ 2 = 1) : x = 1 ∨ x = -1 := by sorry example (h : x ^ 2 = y ^ 2) : x = y ∨ x = -y := by sorry end example (P : Prop) : ¬¬P → P := by intro h cases em P · assumption contradiction example (P : Prop) : ¬¬P → P := by intro h by_cases h' : P · assumption contradiction example (P Q : Prop) : P → Q ↔ ¬P ∨ Q := by sorry
-
-
-
@@ -0,0 +1,99 @@import Mathlib.Data.Real.Basic namespace C03S06 def ConvergesTo (s : ℕ → ℝ) (a : ℝ) := ∀ ε > 0, ∃ N, ∀ n ≥ N, abs (s n - a) < ε example : (fun x y : ℝ => (x + y) ^ 2) = fun x y : ℝ => x ^ 2 + 2 * x * y + y ^ 2 := by ext ring example (a b : ℝ) : abs a = abs (a - b + b) := by congr ring example {a : ℝ} (h : 1 < a) : a < a * a := by convert(mul_lt_mul_right _).2 h · rw [one_mul] exact lt_trans zero_lt_one h theorem convergesTo_const (a : ℝ) : ConvergesTo (fun x : ℕ => a) a := by intro ε εpos use 0 intro n nge; dsimp rw [sub_self, abs_zero] apply εpos theorem convergesTo_add {s t : ℕ → ℝ} {a b : ℝ} (cs : ConvergesTo s a) (ct : ConvergesTo t b) : ConvergesTo (fun n => s n + t n) (a + b) := by intro ε εpos dsimp have ε2pos : 0 < ε / 2 := by linarith cases' cs (ε / 2) ε2pos with Ns hs cases' ct (ε / 2) ε2pos with Nt ht use max Ns Nt sorry theorem convergesTo_mul_const {s : ℕ → ℝ} {a : ℝ} (c : ℝ) (cs : ConvergesTo s a) : ConvergesTo (fun n => c * s n) (c * a) := by by_cases h : c = 0 · convert convergesTo_const 0 · rw [h, MulZeroClass.zero_mul] rw [h, MulZeroClass.zero_mul] have acpos : 0 < abs c := abs_pos.mpr h sorry theorem exists_abs_le_of_convergesTo {s : ℕ → ℝ} {a : ℝ} (cs : ConvergesTo s a) : ∃ N b, ∀ n, N ≤ n → abs (s n) < b := by cases' cs 1 zero_lt_one with N h use N, abs a + 1 sorry theorem aux {s t : ℕ → ℝ} {a : ℝ} (cs : ConvergesTo s a) (ct : ConvergesTo t 0) : ConvergesTo (fun n => s n * t n) 0 := by intro ε εpos dsimp rcases exists_abs_le_of_convergesTo cs with ⟨N₀, B, h₀⟩ have Bpos : 0 < B := lt_of_le_of_lt (abs_nonneg _) (h₀ N₀ (le_refl _)) have pos₀ : ε / B > 0 := div_pos εpos Bpos cases' ct _ pos₀ with N₁ h₁ sorry theorem convergesTo_mul {s t : ℕ → ℝ} {a b : ℝ} (cs : ConvergesTo s a) (ct : ConvergesTo t b) : ConvergesTo (fun n => s n * t n) (a * b) := by have h₁ : ConvergesTo (fun n => s n * (t n + -b)) 0 := by apply aux cs convert convergesTo_add ct (convergesTo_const (-b)) ring have := convergesTo_add h₁ (convergesTo_mul_const b cs) convert convergesTo_add h₁ (convergesTo_mul_const b cs) using 1 · ext; ring ring theorem convergesTo_unique {s : ℕ → ℝ} {a b : ℝ} (sa : ConvergesTo s a) (sb : ConvergesTo s b) : a = b := by by_contra abne have : abs (a - b) > 0 := by sorry let ε := abs (a - b) / 2 have εpos : ε > 0 := by change abs (a - b) / 2 > 0 linarith cases' sa ε εpos with Na hNa cases' sb ε εpos with Nb hNb let N := max Na Nb have absa : abs (s N - a) < ε := by sorry have absb : abs (s N - b) < ε := by sorry have : abs (a - b) < abs (a - b) := by sorry exact lt_irrefl _ this section variable {α : Type _} [LinearOrder α] def ConvergesTo' (s : α → ℝ) (a : ℝ) := ∀ ε > 0, ∃ N, ∀ n ≥ N, abs (s n - a) < ε end
-
-
-
@@ -0,0 +1,129 @@import Mathlib.Data.Real.Basic namespace C03S01 def FnUb (f : ℝ → ℝ) (a : ℝ) : Prop := ∀ x, f x ≤ a def FnLb (f : ℝ → ℝ) (a : ℝ) : Prop := ∀ x, a ≤ f x section variable (f g : ℝ → ℝ) (a b : ℝ) example (hfa : FnLb f a) (hgb : FnLb g b) : FnLb (fun x => f x + g x) (a + b) := by intro x apply add_le_add apply hfa apply hgb example (nnf : FnLb f 0) (nng : FnLb g 0) : FnLb (fun x => f x * g x) 0 := by intro x apply mul_nonneg apply nnf apply nng example (hfa : FnUb f a) (hfb : FnUb g b) (nng : FnLb g 0) (nna : 0 ≤ a) : FnUb (fun x => f x * g x) (a * b) := by intro x apply mul_le_mul apply hfa apply hfb apply nng apply nna end section variable (f g : ℝ → ℝ) example {c : ℝ} (mf : Monotone f) (nnc : 0 ≤ c) : Monotone fun x => c * f x := by intro a b aleb apply mul_le_mul_of_nonneg_left _ nnc apply mf aleb example {c : ℝ} (mf : Monotone f) (nnc : 0 ≤ c) : Monotone fun x => c * f x := fun a b aleb => mul_le_mul_of_nonneg_left (mf aleb) nnc example (mf : Monotone f) (mg : Monotone g) : Monotone fun x => f (g x) := by intro a b aleb apply mf apply mg apply aleb example (mf : Monotone f) (mg : Monotone g) : Monotone fun x => f (g x) := fun a b aleb => mf (mg aleb) def FnEven (f : ℝ → ℝ) : Prop := ∀ x, f x = f (-x) def FnOdd (f : ℝ → ℝ) : Prop := ∀ x, f x = -f (-x) example (of : FnOdd f) (og : FnOdd g) : FnEven fun x => f x * g x := by intro x calc (fun x => f x * g x) x = f x * g x := rfl _ = f (-x) * g (-x) := by rw [of, og, neg_mul_neg] example (ef : FnEven f) (og : FnOdd g) : FnOdd fun x => f x * g x := by intro x dsimp rw [ef, og, neg_mul_eq_mul_neg] example (ef : FnEven f) (og : FnOdd g) : FnEven fun x => f (g x) := by intro x dsimp rw [og, ← ef] end section variable {α : Type _} (r s t : Set α) example : r ⊆ s → s ⊆ t → r ⊆ t := by intro rsubs ssubt x xr apply ssubt apply rsubs apply xr theorem Subset.trans : r ⊆ s → s ⊆ t → r ⊆ t := fun rsubs ssubt x xr => ssubt (rsubs xr) end section variable {α : Type _} [PartialOrder α] variable (s : Set α) (a b : α) def SetUb (s : Set α) (a : α) := ∀ x, x ∈ s → x ≤ a example (h : SetUb s a) (h' : a ≤ b) : SetUb s b := by intro x xs apply le_trans (h x xs) h' example (h : SetUb s a) (h' : a ≤ b) : SetUb s b := fun x xs => le_trans (h x xs) h' end section open Function example {c : ℝ} (h : c ≠ 0) : Injective fun x => c * x := by intro x₁ x₂ h' apply (mul_right_inj' h).mp h' variable {α : Type _} {β : Type _} {γ : Type _} variable {g : β → γ} {f : α → β} example (injg : Injective g) (injf : Injective f) : Injective fun x => g (f x) := by intro x₁ x₂ h apply injf apply injg apply h end
-
-
-
@@ -0,0 +1,81 @@import Mathlib.Data.Real.Basic namespace C03S02 def FnUb (f : ℝ → ℝ) (a : ℝ) : Prop := ∀ x, f x ≤ a def FnLb (f : ℝ → ℝ) (a : ℝ) : Prop := ∀ x, a ≤ f x def FnHasUb (f : ℝ → ℝ) := ∃ a, FnUb f a def FnHasLb (f : ℝ → ℝ) := ∃ a, FnLb f a theorem fnUb_add {f g : ℝ → ℝ} {a b : ℝ} (hfa : FnUb f a) (hgb : FnUb g b) : FnUb (fun x => f x + g x) (a + b) := fun x => add_le_add (hfa x) (hgb x) section variable {f g : ℝ → ℝ} example (lbf : FnHasLb f) (lbg : FnHasLb g) : FnHasLb fun x => f x + g x := by cases' lbf with a lbfa cases' lbg with b lbgb use a + b intro x exact add_le_add (lbfa x) (lbgb x) example {c : ℝ} (ubf : FnHasUb f) (h : c ≥ 0) : FnHasUb fun x => c * f x := by cases' ubf with a lbfa use c * a intro x exact mul_le_mul_of_nonneg_left (lbfa x) h end section variable {a b c : ℕ} example (divab : a ∣ b) (divbc : b ∣ c) : a ∣ c := by rcases divab with ⟨d, rfl⟩ rcases divbc with ⟨e, rfl⟩ use d * e; ring example (divab : a ∣ b) (divac : a ∣ c) : a ∣ b + c := by rcases divab with ⟨d, rfl⟩ rcases divac with ⟨e, rfl⟩ use d + e; ring end section open Function example {c : ℝ} (h : c ≠ 0) : Surjective fun x => c * x := by intro x use x / c dsimp; rw [mul_div_cancel' _ h] example {c : ℝ} (h : c ≠ 0) : Surjective fun x => c * x := by intro x use x / c field_simp [h] ; ring end section open Function variable {α : Type _} {β : Type _} {γ : Type _} variable {g : β → γ} {f : α → β} example (surjg : Surjective g) (surjf : Surjective f) : Surjective fun x => g (f x) := by intro z rcases surjg z with ⟨y, rfl⟩ rcases surjf y with ⟨x, rfl⟩ use x end
-
-
-
@@ -0,0 +1,111 @@import Mathlib.Data.Real.Basic namespace C03S03 section variable (a b : ℝ) def FnUb (f : ℝ → ℝ) (a : ℝ) : Prop := ∀ x, f x ≤ a def FnLb (f : ℝ → ℝ) (a : ℝ) : Prop := ∀ x, a ≤ f x def FnHasUb (f : ℝ → ℝ) := ∃ a, FnUb f a def FnHasLb (f : ℝ → ℝ) := ∃ a, FnLb f a variable (f : ℝ → ℝ) example (h : ∀ a, ∃ x, f x < a) : ¬FnHasLb f := by rintro ⟨a, ha⟩ rcases h a with ⟨x, hx⟩ have := ha x linarith example : ¬FnHasUb fun x => x := by rintro ⟨a, ha⟩ have : a + 1 ≤ a := ha (a + 1) linarith example (h : Monotone f) (h' : f a < f b) : a < b := by apply lt_of_not_ge intro h'' apply absurd h' apply not_lt_of_ge (h h'') example (h : a ≤ b) (h' : f b < f a) : ¬Monotone f := by intro h'' apply absurd h' apply not_lt_of_ge apply h'' h example : ¬∀ {f : ℝ → ℝ}, Monotone f → ∀ {a b}, f a ≤ f b → a ≤ b := by intro h let f := fun x : ℝ => (0 : ℝ) have monof : Monotone f := by intro a b leab rfl have h' : f 1 ≤ f 0 := le_refl _ have : (1 : ℝ) ≤ 0 := h monof h' linarith example (x : ℝ) (h : ∀ ε > 0, x < ε) : x ≤ 0 := by apply le_of_not_gt intro h' linarith [h _ h'] end section variable {α : Type _} (P : α → Prop) (Q : Prop) example (h : ¬∃ x, P x) : ∀ x, ¬P x := by intro x Px apply h use x exact Px example (h : ∀ x, ¬P x) : ¬∃ x, P x := by rintro ⟨x, Px⟩ exact h x Px example (h : ∃ x, ¬P x) : ¬∀ x, P x := by intro h' rcases h with ⟨x, nPx⟩ apply nPx apply h' example (h : ¬¬Q) : Q := by by_contra h' exact h h' example (h : Q) : ¬¬Q := by intro h' exact h' h end section variable (f : ℝ → ℝ) example (h : ¬FnHasUb f) : ∀ a, ∃ x, f x > a := by intro a by_contra h' apply h use a intro x apply le_of_not_gt intro h'' apply h' use x exact h'' example (h : ¬Monotone f) : ∃ x y, x ≤ y ∧ f y < f x := by rw [Monotone] at h push_neg at h exact h end
-
-
-
@@ -0,0 +1,94 @@import Mathlib.Data.Real.Basic import Mathlib.Data.Nat.Prime import Mathlib.Tactic.NormNum namespace C03S04 example {m n : ℕ} (h : m ∣ n ∧ m ≠ n) : m ∣ n ∧ ¬n ∣ m := by cases' h with h0 h1 constructor · exact h0 intro h2 apply h1 apply Nat.dvd_antisymm h0 h2 example {x y : ℝ} : x ≤ y ∧ ¬y ≤ x ↔ x ≤ y ∧ x ≠ y := by constructor · rintro ⟨h0, h1⟩ constructor · exact h0 intro h2 apply h1 rw [h2] rintro ⟨h0, h1⟩ constructor · exact h0 intro h2 apply h1 apply le_antisymm h0 h2 theorem aux {x y : ℝ} (h : x ^ 2 + y ^ 2 = 0) : x = 0 := have h' : x ^ 2 = 0 := by linarith [pow_two_nonneg x, pow_two_nonneg y] pow_eq_zero h' example (x y : ℝ) : x ^ 2 + y ^ 2 = 0 ↔ x = 0 ∧ y = 0 := by constructor · intro h constructor · exact aux h rw [add_comm] at h exact aux h rintro ⟨rfl, rfl⟩ norm_num theorem not_monotone_iff {f : ℝ → ℝ} : ¬Monotone f ↔ ∃ x y, x ≤ y ∧ f x > f y := by rw [Monotone] push_neg rfl example : ¬Monotone fun x : ℝ => -x := by rw [not_monotone_iff] use 0, 1 norm_num section variable {α : Type _} [PartialOrder α] variable (a b : α) example : a < b ↔ a ≤ b ∧ a ≠ b := by rw [lt_iff_le_not_le] constructor · rintro ⟨h0, h1⟩ constructor · exact h0 intro h2 apply h1 rw [h2] rintro ⟨h0, h1⟩ constructor · exact h0 intro h2 apply h1 apply le_antisymm h0 h2 end section variable {α : Type _} [Preorder α] variable (a b c : α) example : ¬a < a := by rw [lt_iff_le_not_le] rintro ⟨h0, h1⟩ exact h1 h0 example : a < b → b < c → a < c := by simp only [lt_iff_le_not_le] rintro ⟨h0, h1⟩ ⟨h2, h3⟩ constructor · apply le_trans h0 h2 intro h4 apply h1 apply le_trans h2 h4 end
-
-
-
@@ -0,0 +1,141 @@import Mathlib.Data.Real.Basic namespace C03S05 section variable {x y : ℝ} namespace MyAbs theorem le_abs_self (x : ℝ) : x ≤ abs x := by cases' le_or_gt 0 x with h h · rw [abs_of_nonneg h] rw [abs_of_neg h] linarith theorem neg_le_abs_self (x : ℝ) : -x ≤ abs x := by cases' le_or_gt 0 x with h h · rw [abs_of_nonneg h] linarith rw [abs_of_neg h] theorem abs_add (x y : ℝ) : abs (x + y) ≤ abs x + abs y := by cases' le_or_gt 0 (x + y) with h h · rw [abs_of_nonneg h] linarith [le_abs_self x, le_abs_self y] rw [abs_of_neg h] linarith [neg_le_abs_self x, neg_le_abs_self y] theorem lt_abs : x < abs y ↔ x < y ∨ x < -y := by cases' le_or_gt 0 y with h h · rw [abs_of_nonneg h] constructor · intro h' left exact h' intro h' cases' h' with h' h' · exact h' linarith rw [abs_of_neg h] constructor · intro h' right exact h' intro h' cases' h' with h' h' · linarith exact h' theorem abs_lt : abs x < y ↔ -y < x ∧ x < y := by cases' le_or_gt 0 x with h h · rw [abs_of_nonneg h] constructor · intro h' constructor · linarith exact h' intro h' cases' h' with h1 h2 exact h2 rw [abs_of_neg h] constructor · intro h' constructor · linarith linarith intro h' linarith end MyAbs end example {z : ℝ} (h : ∃ x y, z = x ^ 2 + y ^ 2 ∨ z = x ^ 2 + y ^ 2 + 1) : z ≥ 0 := by rcases h with ⟨x, y, rfl | rfl⟩ <;> linarith [sq_nonneg x, sq_nonneg y] example {x : ℝ} (h : x ^ 2 = 1) : x = 1 ∨ x = -1 := by have h' : x ^ 2 - 1 = 0 := by rw [h, sub_self] have h'' : (x + 1) * (x - 1) = 0 := by rw [← h'] ring cases' eq_zero_or_eq_zero_of_mul_eq_zero h'' with h1 h1 · right exact eq_neg_iff_add_eq_zero.mpr h1 left exact eq_of_sub_eq_zero h1 example {x y : ℝ} (h : x ^ 2 = y ^ 2) : x = y ∨ x = -y := by have h' : x ^ 2 - y ^ 2 = 0 := by rw [h, sub_self] have h'' : (x + y) * (x - y) = 0 := by rw [← h'] ring cases' eq_zero_or_eq_zero_of_mul_eq_zero h'' with h1 h1 · right exact eq_neg_iff_add_eq_zero.mpr h1 left exact eq_of_sub_eq_zero h1 section variable {R : Type _} [CommRing R] [IsDomain R] variable (x y : R) example (h : x ^ 2 = 1) : x = 1 ∨ x = -1 := by have h' : x ^ 2 - 1 = 0 := by rw [h, sub_self] have h'' : (x + 1) * (x - 1) = 0 := by rw [← h'] ring cases' eq_zero_or_eq_zero_of_mul_eq_zero h'' with h1 h1 · right exact eq_neg_iff_add_eq_zero.mpr h1 left exact eq_of_sub_eq_zero h1 example (h : x ^ 2 = y ^ 2) : x = y ∨ x = -y := by have h' : x ^ 2 - y ^ 2 = 0 := by rw [h, sub_self] have h'' : (x + y) * (x - y) = 0 := by rw [← h'] ring cases' eq_zero_or_eq_zero_of_mul_eq_zero h'' with h1 h1 · right exact eq_neg_iff_add_eq_zero.mpr h1 left exact eq_of_sub_eq_zero h1 end example (P Q : Prop) : P → Q ↔ ¬P ∨ Q := by constructor · intro h by_cases h' : P · right exact h h' left exact h' rintro (h | h) · intro h' exact absurd h' h intro exact h
-
-
-
@@ -0,0 +1,127 @@import Mathlib.Data.Real.Basic namespace C03S06 def ConvergesTo (s : ℕ → ℝ) (a : ℝ) := ∀ ε > 0, ∃ N, ∀ n ≥ N, abs (s n - a) < ε theorem convergesTo_const (a : ℝ) : ConvergesTo (fun x : ℕ => a) a := by intro ε εpos use 0 intro n nge; dsimp rw [sub_self, abs_zero] apply εpos theorem convergesTo_add {s t : ℕ → ℝ} {a b : ℝ} (cs : ConvergesTo s a) (ct : ConvergesTo t b) : ConvergesTo (fun n => s n + t n) (a + b) := by intro ε εpos dsimp have ε2pos : 0 < ε / 2 := by linarith cases' cs (ε / 2) ε2pos with Ns hs cases' ct (ε / 2) ε2pos with Nt ht use max Ns Nt intro n hn have ngeNs : n ≥ Ns := le_of_max_le_left hn have ngeNt : n ≥ Nt := le_of_max_le_right hn calc |s n + t n - (a + b)| = |s n - a + (t n - b)| := by congr ring _ ≤ |s n - a| + |t n - b| := (abs_add _ _) _ < ε / 2 + ε / 2 := (add_lt_add (hs n ngeNs) (ht n ngeNt)) _ = ε := by norm_num theorem convergesTo_mul_const {s : ℕ → ℝ} {a : ℝ} (c : ℝ) (cs : ConvergesTo s a) : ConvergesTo (fun n => c * s n) (c * a) := by by_cases h : c = 0 · convert convergesTo_const 0 · rw [h, MulZeroClass.zero_mul] rw [h, MulZeroClass.zero_mul] have acpos : 0 < abs c := abs_pos.mpr h intro ε εpos dsimp have εcpos : 0 < ε / abs c := by apply div_pos εpos acpos cases' cs (ε / abs c) εcpos with Ns hs use Ns intro n ngt calc |c * s n - c * a| = |c| * |s n - a| := by rw [← abs_mul, mul_sub] _ < |c| * (ε / |c|) := (mul_lt_mul_of_pos_left (hs n ngt) acpos) _ = ε := mul_div_cancel' _ (ne_of_lt acpos).symm theorem exists_abs_le_of_convergesTo {s : ℕ → ℝ} {a : ℝ} (cs : ConvergesTo s a) : ∃ N b, ∀ n, N ≤ n → abs (s n) < b := by cases' cs 1 zero_lt_one with N h use N, abs a + 1 intro n ngt calc |s n| = |s n - a + a| := by congr abel _ ≤ |s n - a| + |a| := (abs_add _ _) _ < |a| + 1 := by linarith [h n ngt] theorem aux {s t : ℕ → ℝ} {a : ℝ} (cs : ConvergesTo s a) (ct : ConvergesTo t 0) : ConvergesTo (fun n => s n * t n) 0 := by intro ε εpos dsimp rcases exists_abs_le_of_convergesTo cs with ⟨N₀, B, h₀⟩ have Bpos : 0 < B := lt_of_le_of_lt (abs_nonneg _) (h₀ N₀ (le_refl _)) have pos₀ : ε / B > 0 := div_pos εpos Bpos cases' ct _ pos₀ with N₁ h₁ use max N₀ N₁ intro n ngt have ngeN₀ : n ≥ N₀ := le_of_max_le_left ngt have ngeN₁ : n ≥ N₁ := le_of_max_le_right ngt calc |s n * t n - 0| = |s n| * |t n - 0| := by rw [sub_zero, abs_mul, sub_zero] _ < B * (ε / B) := (mul_lt_mul'' (h₀ n ngeN₀) (h₁ n ngeN₁) (abs_nonneg _) (abs_nonneg _)) _ = ε := mul_div_cancel' _ (ne_of_lt Bpos).symm theorem convergesTo_mul {s t : ℕ → ℝ} {a b : ℝ} (cs : ConvergesTo s a) (ct : ConvergesTo t b) : ConvergesTo (fun n => s n * t n) (a * b) := by have h₁ : ConvergesTo (fun n => s n * (t n + -b)) 0 := by apply aux cs convert convergesTo_add ct (convergesTo_const (-b)) ring have := convergesTo_add h₁ (convergesTo_mul_const b cs) convert convergesTo_add h₁ (convergesTo_mul_const b cs) using 1 · ext; ring ring theorem convergesTo_unique {s : ℕ → ℝ} {a b : ℝ} (sa : ConvergesTo s a) (sb : ConvergesTo s b) : a = b := by by_contra abne have : abs (a - b) > 0 := by apply lt_of_le_of_ne · apply abs_nonneg intro h'' apply abne apply eq_of_abs_sub_eq_zero h''.symm let ε := abs (a - b) / 2 have εpos : ε > 0 := by change abs (a - b) / 2 > 0 linarith cases' sa ε εpos with Na hNa cases' sb ε εpos with Nb hNb let N := max Na Nb have absa : abs (s N - a) < ε := by apply hNa apply le_max_left have absb : abs (s N - b) < ε := by apply hNb apply le_max_right have : abs (a - b) < abs (a - b) calc abs (a - b) = abs (-(s N - a) + (s N - b)) := by congr ring _ ≤ abs (-(s N - a)) + abs (s N - b) := (abs_add _ _) _ = abs (s N - a) + abs (s N - b) := by rw [abs_neg] _ < ε + ε := (add_lt_add absa absb) _ = abs (a - b) := by norm_num exact lt_irrefl _ this
-
-
-
@@ -0,0 +1,247 @@import Mathlib.Data.Set.Lattice import Mathlib.Data.Nat.Prime import Mathlib.Data.Nat.Parity import Mathlib.Tactic section variable {α : Type _} variable (s t u : Set α) open Set example (h : s ⊆ t) : s ∩ u ⊆ t ∩ u := by rw [subset_def, inter_def, inter_def] rw [subset_def] at h dsimp rintro x ⟨xs, xu⟩ exact ⟨h _ xs, xu⟩ example (h : s ⊆ t) : s ∩ u ⊆ t ∩ u := by simp only [subset_def, mem_inter_iff] at * rintro x ⟨xs, xu⟩ exact ⟨h _ xs, xu⟩ example (h : s ⊆ t) : s ∩ u ⊆ t ∩ u := by intro x xsu exact ⟨h xsu.1, xsu.2⟩ theorem foo (h : s ⊆ t) : s ∩ u ⊆ t ∩ u := fun x ⟨xs, xu⟩ => ⟨h xs, xu⟩ example (h : s ⊆ t) : s ∩ u ⊆ t ∩ u := fun x ⟨xs, xu⟩ => ⟨h xs, xu⟩ example : s ∩ (t ∪ u) ⊆ s ∩ t ∪ s ∩ u := by intro x hx have xs : x ∈ s := hx.1 have xtu : x ∈ t ∪ u := hx.2 cases' xtu with xt xu · left show x ∈ s ∩ t exact ⟨xs, xt⟩ right show x ∈ s ∩ u exact ⟨xs, xu⟩ example : s ∩ (t ∪ u) ⊆ s ∩ t ∪ s ∩ u := by rintro x ⟨xs, xt | xu⟩ · left exact ⟨xs, xt⟩ right; exact ⟨xs, xu⟩ example : s ∩ t ∪ s ∩ u ⊆ s ∩ (t ∪ u) := by sorry example : (s \ t) \ u ⊆ s \ (t ∪ u) := by intro x xstu have xs : x ∈ s := xstu.1.1 have xnt : x ∉ t := xstu.1.2 have xnu : x ∉ u := xstu.2 constructor · exact xs intro xtu -- x ∈ t ∨ x ∈ u cases' xtu with xt xu · show False exact xnt xt show False; exact xnu xu example : (s \ t) \ u ⊆ s \ (t ∪ u) := by rintro x ⟨⟨xs, xnt⟩, xnu⟩ use xs rintro (xt | xu) <;> contradiction example : s \ (t ∪ u) ⊆ (s \ t) \ u := by sorry example : s ∩ t = t ∩ s := by ext x simp only [mem_inter_iff] constructor · rintro ⟨xs, xt⟩ exact ⟨xt, xs⟩ rintro ⟨xt, xs⟩; exact ⟨xs, xt⟩ example : s ∩ t = t ∩ s := Set.ext fun x => ⟨fun ⟨xs, xt⟩ => ⟨xt, xs⟩, fun ⟨xt, xs⟩ => ⟨xs, xt⟩⟩ example : s ∩ t = t ∩ s := by ext x; simp [and_comm] example : s ∩ t = t ∩ s := by apply Subset.antisymm · rintro x ⟨xs, xt⟩ exact ⟨xt, xs⟩ rintro x ⟨xt, xs⟩; exact ⟨xs, xt⟩ example : s ∩ t = t ∩ s := Subset.antisymm sorry sorry example : s ∩ (s ∪ t) = s := by sorry example : s ∪ s ∩ t = s := by sorry example : s \ t ∪ t = s ∪ t := by sorry example : s \ t ∪ t \ s = (s ∪ t) \ (s ∩ t) := by sorry def evens : Set ℕ := { n | Even n } def odds : Set ℕ := { n | ¬Even n } example : evens ∪ odds = univ := by rw [evens, odds] ext n simp apply Classical.em example (x : ℕ) (h : x ∈ (∅ : Set ℕ)) : False := h example (x : ℕ) : x ∈ (univ : Set ℕ) := trivial example : { n | Nat.Prime n } ∩ { n | n > 2 } ⊆ { n | ¬Even n } := by sorry #print Prime #print Nat.Prime example (n : ℕ) : Prime n ↔ Nat.Prime n := Nat.prime_iff.symm example (n : ℕ) (h : Prime n) : Nat.Prime n := by rw [Nat.prime_iff] exact h example (n : ℕ) (h : Prime n) : Nat.Prime n := by rwa [Nat.prime_iff] end section variable (s t : Set ℕ) example (h₀ : ∀ x ∈ s, ¬Even x) (h₁ : ∀ x ∈ s, Prime x) : ∀ x ∈ s, ¬Even x ∧ Prime x := by intro x xs constructor · apply h₀ x xs apply h₁ x xs example (h : ∃ x ∈ s, ¬Even x ∧ Prime x) : ∃ x ∈ s, Prime x := by rcases h with ⟨x, xs, _, prime_x⟩ use x, xs exact prime_x section variable (ssubt : s ⊆ t) example (h₀ : ∀ x ∈ t, ¬Even x) (h₁ : ∀ x ∈ t, Prime x) : ∀ x ∈ s, ¬Even x ∧ Prime x := by sorry example (h : ∃ x ∈ s, ¬Even x ∧ Prime x) : ∃ x ∈ t, Prime x := by sorry end end section variable {α I : Type _} variable (A B : I → Set α) variable (s : Set α) open Set example : (s ∩ ⋃ i, A i) = ⋃ i, A i ∩ s := by ext x simp only [mem_inter_iff, mem_iUnion] constructor · rintro ⟨xs, ⟨i, xAi⟩⟩ exact ⟨i, xAi, xs⟩ rintro ⟨i, xAi, xs⟩ exact ⟨xs, ⟨i, xAi⟩⟩ example : (⋂ i, A i ∩ B i) = (⋂ i, A i) ∩ ⋂ i, B i := by ext x simp only [mem_inter_iff, mem_iInter] constructor · intro h constructor · intro i exact (h i).1 intro i exact (h i).2 rintro ⟨h1, h2⟩ i constructor · exact h1 i exact h2 i example : (s ∪ ⋂ i, A i) = ⋂ i, A i ∪ s := by sorry def primes : Set ℕ := { x | Nat.Prime x } example : (⋃ p ∈ primes, { x | p ^ 2 ∣ x }) = { x | ∃ p ∈ primes, p ^ 2 ∣ x } :=by ext rw [mem_iUnion₂] simp example : (⋃ p ∈ primes, { x | p ^ 2 ∣ x }) = { x | ∃ p ∈ primes, p ^ 2 ∣ x } := by ext simp example : (⋂ p ∈ primes, { x | ¬p ∣ x }) ⊆ { x | x = 1 } := by intro x contrapose! simp apply Nat.exists_prime_and_dvd example : (⋃ p ∈ primes, { x | x ≤ p }) = univ := by sorry end section open Set variable {α : Type _} (s : Set (Set α)) example : ⋃₀ s = ⋃ t ∈ s, t := by ext x rw [mem_iUnion₂] simp example : ⋂₀ s = ⋂ t ∈ s, t := by ext x rw [mem_iInter₂] rfl end
-
-
-
@@ -0,0 +1,213 @@import Mathlib.Data.Set.Lattice import Mathlib.Data.Set.Function import Mathlib.Analysis.SpecialFunctions.Log.Basic section variable {α β : Type _} variable (f : α → β) variable (s t : Set α) variable (u v : Set β) open Function open Set example : f ⁻¹' (u ∩ v) = f ⁻¹' u ∩ f ⁻¹' v := by ext rfl example : f '' (s ∪ t) = f '' s ∪ f '' t := by ext y; constructor · rintro ⟨x, xs | xt, rfl⟩ · left use x, xs right use x, xt rintro (⟨x, xs, rfl⟩ | ⟨x, xt, rfl⟩) · use x, Or.inl xs use x, Or.inr xt example : s ⊆ f ⁻¹' (f '' s) := by intro x xs show f x ∈ f '' s use x, xs example : f '' s ⊆ v ↔ s ⊆ f ⁻¹' v := by sorry example (h : Injective f) : f ⁻¹' (f '' s) ⊆ s := by sorry example : f '' (f ⁻¹' u) ⊆ u := by sorry example (h : Surjective f) : u ⊆ f '' (f ⁻¹' u) := by sorry example (h : s ⊆ t) : f '' s ⊆ f '' t := by sorry example (h : u ⊆ v) : f ⁻¹' u ⊆ f ⁻¹' v := by sorry example : f ⁻¹' (u ∪ v) = f ⁻¹' u ∪ f ⁻¹' v := by sorry example : f '' (s ∩ t) ⊆ f '' s ∩ f '' t := by sorry example (h : Injective f) : f '' s ∩ f '' t ⊆ f '' (s ∩ t) := by sorry example : f '' s \ f '' t ⊆ f '' (s \ t) := by sorry example : f ⁻¹' u \ f ⁻¹' v ⊆ f ⁻¹' (u \ v) := by sorry example : f '' s ∩ v = f '' (s ∩ f ⁻¹' v) := by sorry example : f '' (s ∩ f ⁻¹' u) ⊆ f '' s ∪ u := by sorry example : s ∩ f ⁻¹' u ⊆ f ⁻¹' (f '' s ∩ u) := by sorry example : s ∪ f ⁻¹' u ⊆ f ⁻¹' (f '' s ∪ u) := by sorry variable {I : Type _} (A : I → Set α) (B : I → Set β) example : (f '' ⋃ i, A i) = ⋃ i, f '' A i := by ext y; simp constructor · rintro ⟨x, ⟨i, xAi⟩, fxeq⟩ use i, x exact ⟨xAi, fxeq⟩ rintro ⟨i, x, xAi, fxeq⟩ exact ⟨x, ⟨i, xAi⟩, fxeq⟩ example : (f '' ⋂ i, A i) ⊆ ⋂ i, f '' A i := by intro y; simp intro x h fxeq i use x exact ⟨h i, fxeq⟩ example (i : I) (injf : Injective f) : (⋂ i, f '' A i) ⊆ f '' ⋂ i, A i := by intro y; simp intro h rcases h i with ⟨x, xAi, fxeq⟩ use x; constructor · intro i' rcases h i' with ⟨x', x'Ai, fx'eq⟩ have : f x = f x' := by rw [fxeq, fx'eq] have : x = x' := injf this rw [this] exact x'Ai exact fxeq example : (f ⁻¹' ⋃ i, B i) = ⋃ i, f ⁻¹' B i := by ext x simp example : (f ⁻¹' ⋂ i, B i) = ⋂ i, f ⁻¹' B i := by ext x simp example : InjOn f s ↔ ∀ x₁ ∈ s, ∀ x₂ ∈ s, f x₁ = f x₂ → x₁ = x₂ := Iff.refl _ end section open Set Real example : InjOn log { x | x > 0 } := by intro x xpos y ypos intro e -- log x = log y calc x = exp (log x) := by rw [exp_log xpos] _ = exp (log y) := by rw [e] _ = y := by rw [exp_log ypos] example : range exp = { y | y > 0 } := by ext y; constructor · rintro ⟨x, rfl⟩ apply exp_pos intro ypos use log y rw [exp_log ypos] example : InjOn sqrt { x | x ≥ 0 } := by sorry example : InjOn (fun x => x ^ 2) { x : ℝ | x ≥ 0 } := by sorry example : sqrt '' { x | x ≥ 0 } = { y | y ≥ 0 } := by sorry example : (range fun x => x ^ 2) = { y : ℝ | y ≥ 0 } := by sorry end section variable {α β : Type _} [Inhabited α] #check (default : α) variable (P : α → Prop) (h : ∃ x, P x) #check Classical.choose h example : P (Classical.choose h) := Classical.choose_spec h noncomputable section open Classical def inverse (f : α → β) : β → α := fun y : β => if h : ∃ x, f x = y then Classical.choose h else default theorem inverse_spec {f : α → β} (y : β) (h : ∃ x, f x = y) : f (inverse f y) = y := by rw [inverse]; dsimp; rw [dif_pos h] exact Classical.choose_spec h variable (f : α → β) open Function example : Injective f ↔ LeftInverse (inverse f) f := sorry example : Surjective f ↔ RightInverse (inverse f) f := sorry end section variable {α : Type _} open Function theorem Cantor : ∀ f : α → Set α, ¬Surjective f := by intro f surjf let S := { i | i ∉ f i } rcases surjf S with ⟨j, h⟩ have h₁ : j ∉ f j := by intro h' have : j ∉ f j := by rwa [h] at h' contradiction have h₂ : j ∈ S sorry have h₃ : j ∉ S sorry contradiction -- COMMENTS: TODO: improve this end
-
-
-
@@ -0,0 +1,98 @@import Mathlib.Data.Set.Lattice import Mathlib.Data.Set.Function import Mathlib.Tactic open Set open Function noncomputable section open Classical variable {α β : Type _} [Nonempty β] section variable (f : α → β) (g : β → α) def sbAux : ℕ → Set α | 0 => univ \ g '' univ | n + 1 => g '' (f '' sbAux n) def sbSet := ⋃ n, sbAux f g n def sbFun (x : α) : β := if x ∈ sbSet f g then f x else invFun g x theorem sb_right_inv {x : α} (hx : x ∉ sbSet f g) : g (invFun g x) = x := by have : x ∈ g '' univ := by contrapose! hx rw [sbSet, mem_iUnion] use 0 rw [sbAux, mem_diff] sorry have : ∃ y, g y = x := by sorry sorry theorem sb_injective (hf : Injective f) (hg : Injective g) : Injective (sbFun f g) := by set A := sbSet f g with A_def set h := sbFun f g with h_def intro x₁ x₂ intro (hxeq : h x₁ = h x₂) show x₁ = x₂ simp only [h_def, sbFun, ← A_def] at hxeq by_cases xA : x₁ ∈ A ∨ x₂ ∈ A · wlog x₁A : x₁ ∈ A generalizing x₁ x₂ hxeq xA · symm apply this hxeq.symm xA.symm (xA.resolve_left x₁A) have x₂A : x₂ ∈ A := by apply not_imp_self.mp intro (x₂nA : x₂ ∉ A) rw [if_pos x₁A, if_neg x₂nA] at hxeq rw [A_def, sbSet, mem_iUnion] at x₁A have x₂eq : x₂ = g (f x₁) := by sorry rcases x₁A with ⟨n, hn⟩ rw [A_def, sbSet, mem_iUnion] use n + 1 simp [sbAux] exact ⟨x₁, hn, x₂eq.symm⟩ sorry push_neg at xA sorry theorem sb_surjective (hf : Injective f) (hg : Injective g) : Surjective (sbFun f g) := by set A := sbSet f g with A_def set h := sbFun f g with h_def intro y by_cases gyA : g y ∈ A · rw [A_def, sbSet, mem_iUnion] at gyA rcases gyA with ⟨n, hn⟩ cases' n with n · simp [sbAux] at hn simp [sbAux] at hn rcases hn with ⟨x, xmem, hx⟩ use x have : x ∈ A := by rw [A_def, sbSet, mem_iUnion] exact ⟨n, xmem⟩ simp only [h_def, sbFun, if_pos this] exact hg hx sorry end theorem schroeder_bernstein {f : α → β} {g : β → α} (hf : Injective f) (hg : Injective g) : ∃ h : α → β, Bijective h := ⟨sbFun f g, sb_injective f g hf hg, sb_surjective f g hf hg⟩ -- Auxiliary information section variable (g : β → α) (x : α) #check (invFun g : α → β) #check (leftInverse_invFun : Injective g → LeftInverse (invFun g) g) #check (leftInverse_invFun : Injective g → ∀ y, invFun g (g y) = y) #check (invFun_eq : (∃ y, g y = x) → g (invFun g x) = x) end
-
-
-
@@ -0,0 +1,158 @@import Mathlib.Data.Set.Lattice import Mathlib.Data.Nat.Prime import Mathlib.Data.Nat.Parity import Mathlib.Tactic section variable {α : Type _} variable (s t u : Set α) open Set example : s ∩ t ∪ s ∩ u ⊆ s ∩ (t ∪ u) := by rintro x (⟨xs, xt⟩ | ⟨xs, xu⟩) · use xs left exact xt use xs; right; exact xu example : s \ (t ∪ u) ⊆ (s \ t) \ u := by rintro x ⟨xs, xntu⟩ constructor use xs · intro xt exact xntu (Or.inl xt) intro xu apply xntu (Or.inr xu) example : s ∩ t = t ∩ s := Subset.antisymm (fun x ⟨xs, xt⟩ => ⟨xt, xs⟩) fun x ⟨xt, xs⟩ => ⟨xs, xt⟩ example : s ∩ (s ∪ t) = s := by ext x; constructor · rintro ⟨xs, _⟩ exact xs intro xs use xs; left; exact xs example : s ∪ s ∩ t = s := by ext x; constructor · rintro (xs | ⟨xs, xt⟩) <;> exact xs intro xs; left; exact xs example : s \ t ∪ t = s ∪ t := by ext x; constructor · rintro (⟨xs, nxt⟩ | xt) · left exact xs right exact xt by_cases h : x ∈ t · intro right exact h rintro (xs | xt) · left use xs exact h right; exact xt example : s \ t ∪ t \ s = (s ∪ t) \ (s ∩ t) := by ext x; constructor · rintro (⟨xs, xnt⟩ | ⟨xt, xns⟩) · constructor left exact xs rintro ⟨_, xt⟩ contradiction constructor right exact xt rintro ⟨xs, _⟩ contradiction rintro ⟨xs | xt, nxst⟩ · left use xs intro xt apply nxst constructor <;> assumption right; use xt; intro xs apply nxst constructor <;> assumption example : { n | Nat.Prime n } ∩ { n | n > 2 } ⊆ { n | ¬Even n } := by intro n simp intro nprime cases' Nat.Prime.eq_two_or_odd nprime with h h · rw [h] intro linarith rw [Nat.even_iff, h] norm_num end section variable (s t : Set ℕ) section variable (ssubt : s ⊆ t) example (h₀ : ∀ x ∈ t, ¬Even x) (h₁ : ∀ x ∈ t, Prime x) : ∀ x ∈ s, ¬Even x ∧ Prime x := by intro x xs constructor · apply h₀ x (ssubt xs) apply h₁ x (ssubt xs) example (h : ∃ x ∈ s, ¬Even x ∧ Prime x) : ∃ x ∈ t, Prime x := by rcases h with ⟨x, xs, _, px⟩ use x, ssubt xs exact px end end section variable {α I : Type _} variable (A B : I → Set α) variable (s : Set α) open Set example : (s ∪ ⋂ i, A i) = ⋂ i, A i ∪ s := by ext x simp only [mem_union, mem_iInter] constructor · rintro (xs | xI) · intro i right exact xs intro i left exact xI i intro h by_cases xs : x ∈ s · left exact xs right intro i cases h i · assumption contradiction def primes : Set ℕ := { x | Nat.Prime x } example : (⋃ p ∈ primes, { x | x ≤ p }) = univ := by apply eq_univ_of_forall intro x simp rcases Nat.exists_infinite_primes x with ⟨p, primep, pge⟩ use p, pge exact primep end
-
-
-
@@ -0,0 +1,252 @@import Mathlib.Data.Set.Lattice import Mathlib.Data.Set.Function import Mathlib.Analysis.SpecialFunctions.Log.Basic section variable {α β : Type _} variable (f : α → β) variable (s t : Set α) variable (u v : Set β) open Function open Set example : f '' s ⊆ v ↔ s ⊆ f ⁻¹' v := by constructor · intro h x xs have : f x ∈ f '' s := mem_image_of_mem _ xs exact h this intro h y ymem rcases ymem with ⟨x, xs, fxeq⟩ rw [← fxeq] apply h xs example (h : Injective f) : f ⁻¹' (f '' s) ⊆ s := by rintro x ⟨y, ys, fxeq⟩ rw [← h fxeq] exact ys example : f '' (f ⁻¹' u) ⊆ u := by rintro y ⟨x, xmem, rfl⟩ exact xmem example (h : Surjective f) : u ⊆ f '' (f ⁻¹' u) := by intro y yu rcases h y with ⟨x, fxeq⟩ use x constructor · show f x ∈ u rw [fxeq] exact yu exact fxeq example (h : s ⊆ t) : f '' s ⊆ f '' t := by rintro y ⟨x, xs, fxeq⟩ use x, h xs exact fxeq example (h : u ⊆ v) : f ⁻¹' u ⊆ f ⁻¹' v := by intro x; apply h example : f ⁻¹' (u ∪ v) = f ⁻¹' u ∪ f ⁻¹' v := by ext x; rfl example : f '' (s ∩ t) ⊆ f '' s ∩ f '' t := by rintro y ⟨x, ⟨xs, xt⟩, rfl⟩ constructor . use x, xs . use x, xt example (h : Injective f) : f '' s ∩ f '' t ⊆ f '' (s ∩ t) := by rintro y ⟨⟨x₁, x₁s, rfl⟩, ⟨x₂, x₂t, fx₂eq⟩⟩ use x₁ constructor . use x₁s rw [← h fx₂eq] exact x₂t . rfl example : f '' s \ f '' t ⊆ f '' (s \ t) := by rintro y ⟨⟨x₁, x₁s, rfl⟩, h⟩ use x₁ constructor . constructor . exact x₁s . intro h' apply h use x₁, h' . rfl example : f ⁻¹' u \ f ⁻¹' v ⊆ f ⁻¹' (u \ v) := fun x => id example : f '' s ∩ v = f '' (s ∩ f ⁻¹' v) := by ext y; constructor · rintro ⟨⟨x, xs, rfl⟩, fxv⟩ use x, ⟨xs, fxv⟩ rintro ⟨x, ⟨⟨xs, fxv⟩, rfl⟩⟩ exact ⟨⟨x, xs, rfl⟩, fxv⟩ example : f '' (s ∩ f ⁻¹' u) ⊆ f '' s ∩ u := by rintro y ⟨x, ⟨xs, fxu⟩, rfl⟩ exact ⟨⟨x, xs, rfl⟩, fxu⟩ example : s ∩ f ⁻¹' u ⊆ f ⁻¹' (f '' s ∩ u) := by rintro x ⟨xs, fxu⟩ exact ⟨⟨x, xs, rfl⟩, fxu⟩ example : s ∪ f ⁻¹' u ⊆ f ⁻¹' (f '' s ∪ u) := by rintro x (xs | fxu) · left exact ⟨x, xs, rfl⟩ right; exact fxu variable {I : Type _} (A : I → Set α) (B : I → Set β) example : (f '' ⋃ i, A i) = ⋃ i, f '' A i := by ext y; simp constructor · rintro ⟨x, ⟨i, xAi⟩, fxeq⟩ use i, x exact ⟨xAi, fxeq⟩ rintro ⟨i, x, xAi, fxeq⟩ exact ⟨x, ⟨i, xAi⟩, fxeq⟩ example : (f '' ⋂ i, A i) ⊆ ⋂ i, f '' A i := by intro y; simp intro x h fxeq i use x exact ⟨h i, fxeq⟩ example (i : I) (injf : Injective f) : (⋂ i, f '' A i) ⊆ f '' ⋂ i, A i := by intro y; simp intro h rcases h i with ⟨x, xAi, fxeq⟩ use x; constructor · intro i' rcases h i' with ⟨x', x'Ai, fx'eq⟩ have : f x = f x' := by rw [fxeq, fx'eq] have : x = x' := injf this rw [this] exact x'Ai exact fxeq example : (f ⁻¹' ⋃ i, B i) = ⋃ i, f ⁻¹' B i := by ext x simp example : (f ⁻¹' ⋂ i, B i) = ⋂ i, f ⁻¹' B i := by ext x simp end section open Set Real example : InjOn sqrt { x | x ≥ 0 } := by intro x xnonneg y ynonneg intro e calc x = sqrt x ^ 2 := by rw [sq_sqrt xnonneg] _ = sqrt y ^ 2 := by rw [e] _ = y := by rw [sq_sqrt ynonneg] example : InjOn (fun x => x ^ 2) { x : ℝ | x ≥ 0 } := by intro x xnonneg y ynonneg intro e dsimp at * calc x = sqrt (x ^ 2) := by rw [sqrt_sq xnonneg] _ = sqrt (y ^ 2) := by rw [e] _ = y := by rw [sqrt_sq ynonneg] example : sqrt '' { x | x ≥ 0 } = { y | y ≥ 0 } := by ext y; constructor · rintro ⟨x, ⟨xnonneg, rfl⟩⟩ apply sqrt_nonneg intro ynonneg use y ^ 2 dsimp at * constructor apply pow_nonneg ynonneg apply sqrt_sq assumption example : (range fun x => x ^ 2) = { y : ℝ | y ≥ 0 } := by ext y constructor · rintro ⟨x, rfl⟩ dsimp at * apply pow_two_nonneg intro ynonneg use sqrt y exact sq_sqrt ynonneg end section variable {α β : Type _} [Inhabited α] noncomputable section open Classical def inverse (f : α → β) : β → α := fun y : β => if h : ∃ x, f x = y then Classical.choose h else default theorem inverse_spec {f : α → β} (y : β) (h : ∃ x, f x = y) : f (inverse f y) = y := by rw [inverse]; dsimp; rw [dif_pos h] exact Classical.choose_spec h variable (f : α → β) open Function example : Injective f ↔ LeftInverse (inverse f) f := by constructor · intro h y apply h apply inverse_spec use y intro h x1 x2 e rw [← h x1, ← h x2, e] example : Injective f ↔ LeftInverse (inverse f) f := ⟨fun h y => h (inverse_spec _ ⟨y, rfl⟩), fun h x1 x2 e => by rw [← h x1, ← h x2, e]⟩ example : Surjective f ↔ RightInverse (inverse f) f := by constructor · intro h y apply inverse_spec apply h intro h y use inverse f y apply h example : Surjective f ↔ RightInverse (inverse f) f := ⟨fun h y => inverse_spec _ (h _), fun h y => ⟨inverse f y, h _⟩⟩ end section variable {α : Type _} open Function theorem Cantor : ∀ f : α → Set α, ¬Surjective f := by intro f surjf let S := { i | i ∉ f i } rcases surjf S with ⟨j, h⟩ have h₁ : j ∉ f j := by intro h' have : j ∉ f j := by rwa [h] at h' contradiction have h₂ : j ∈ S := h₁ have h₃ : j ∉ S := by rwa [h] at h₁ contradiction end
-
-
-
@@ -0,0 +1,88 @@import Mathlib.Data.Set.Lattice import Mathlib.Data.Set.Function import Mathlib.Tactic open Set open Function noncomputable section open Classical variable {α β : Type _} [Nonempty β] section variable (f : α → β) (g : β → α) def sbAux : ℕ → Set α | 0 => univ \ g '' univ | n + 1 => g '' (f '' sbAux n) def sbSet := ⋃ n, sbAux f g n def sbFun (x : α) : β := if x ∈ sbSet f g then f x else invFun g x theorem sb_right_inv {x : α} (hx : x ∉ sbSet f g) : g (invFun g x) = x := by have : x ∈ g '' univ := by contrapose! hx rw [sbSet, mem_iUnion] use 0 rw [sbAux, mem_diff] exact ⟨mem_univ _, hx⟩ have : ∃ y, g y = x := by simp at this assumption exact invFun_eq this theorem sb_injective (hf : Injective f) (hg : Injective g) : Injective (sbFun f g) := by set A := sbSet f g with A_def set h := sbFun f g with h_def intro x₁ x₂ intro (hxeq : h x₁ = h x₂) show x₁ = x₂ simp only [h_def, sbFun, ← A_def] at hxeq by_cases xA : x₁ ∈ A ∨ x₂ ∈ A · wlog x₁A : x₁ ∈ A generalizing x₁ x₂ hxeq xA · symm apply this hxeq.symm xA.symm (xA.resolve_left x₁A) have x₂A : x₂ ∈ A := by apply not_imp_self.mp intro (x₂nA : x₂ ∉ A) rw [if_pos x₁A, if_neg x₂nA] at hxeq rw [A_def, sbSet, mem_iUnion] at x₁A have x₂eq : x₂ = g (f x₁) := by rw [hxeq, sb_right_inv f g x₂nA] rcases x₁A with ⟨n, hn⟩ rw [A_def, sbSet, mem_iUnion] use n + 1 simp [sbAux] exact ⟨x₁, hn, x₂eq.symm⟩ rw [if_pos x₁A, if_pos x₂A] at hxeq exact hf hxeq push_neg at xA rw [if_neg xA.1, if_neg xA.2] at hxeq rw [← sb_right_inv f g xA.1, hxeq, sb_right_inv f g xA.2] theorem sb_surjective (hf : Injective f) (hg : Injective g) : Surjective (sbFun f g) := by set A := sbSet f g with A_def set h := sbFun f g with h_def intro y by_cases gyA : g y ∈ A · rw [A_def, sbSet, mem_iUnion] at gyA rcases gyA with ⟨n, hn⟩ cases' n with n · simp [sbAux] at hn simp [sbAux] at hn rcases hn with ⟨x, xmem, hx⟩ use x have : x ∈ A := by rw [A_def, sbSet, mem_iUnion] exact ⟨n, xmem⟩ simp only [h_def, sbFun, if_pos this] exact hg hx use g y simp only [h_def, sbFun, if_neg gyA] apply leftInverse_invFun hg end
-
-
-
@@ -0,0 +1,121 @@import Mathlib.Data.Nat.Factorization.Basic import Mathlib.Data.Nat.Prime import Mathlib.Tactic.NormNum.GCD import Mathlib.Tactic.NormNum.Prime #print Nat.coprime example (m n : Nat) (h : m.coprime n) : m.gcd n = 1 := h example (m n : Nat) (h : m.coprime n) : m.gcd n = 1 := by rw [Nat.coprime] at h exact h example : Nat.coprime 12 7 := by norm_num example : Nat.gcd 12 8 = 4 := by norm_num #check @Nat.prime_def_lt example (p : ℕ) (prime_p : Nat.Prime p) : 2 ≤ p ∧ ∀ m : ℕ, m < p → m ∣ p → m = 1 := by rwa [Nat.prime_def_lt] at prime_p #check Nat.Prime.eq_one_or_self_of_dvd example (p : ℕ) (prime_p : Nat.Prime p) : ∀ m : ℕ, m ∣ p → m = 1 ∨ m = p := prime_p.eq_one_or_self_of_dvd example : Nat.Prime 17 := by norm_num -- commonly used example : Nat.Prime 2 := Nat.prime_two example : Nat.Prime 3 := Nat.prime_three #check @Nat.Prime.dvd_mul #check Nat.Prime.dvd_mul Nat.prime_two #check Nat.prime_two.dvd_mul theorem even_of_even_sqr {m : ℕ} (h : 2 ∣ m ^ 2) : 2 ∣ m := by rw [pow_two, Nat.prime_two.dvd_mul] at h cases h <;> assumption example {m : ℕ} (h : 2 ∣ m ^ 2) : 2 ∣ m := Nat.Prime.dvd_of_dvd_pow Nat.prime_two h example (a b c : Nat) (h : a * b = a * c) (h' : a ≠ 0) : b = c := -- library_search suggests the following: (mul_right_inj' h').mp h example {m n : ℕ} (coprime_mn : m.coprime n) : m ^ 2 ≠ 2 * n ^ 2 := by intro sqr_eq have : 2 ∣ m := by sorry obtain ⟨k, meq⟩ := dvd_iff_exists_eq_mul_left.mp this have : 2 * (2 * k ^ 2) = 2 * n ^ 2 := by rw [← sqr_eq, meq] ring have : 2 * k ^ 2 = n ^ 2 := sorry have : 2 ∣ n := by sorry have : 2 ∣ m.gcd n := by sorry have : 2 ∣ 1 := by sorry norm_num at this example {m n p : ℕ} (coprime_mn : m.coprime n) (prime_p : p.Prime) : m ^ 2 ≠ p * n ^ 2 := by sorry #check Nat.factors #check Nat.prime_of_mem_factors #check Nat.prod_factors #check Nat.factors_unique theorem factorization_mul' {m n : ℕ} (mnez : m ≠ 0) (nnez : n ≠ 0) (p : ℕ) : (m * n).factorization p = m.factorization p + n.factorization p := by rw [Nat.factorization_mul mnez nnez] rfl theorem factorization_pow' (n k p : ℕ) : (n ^ k).factorization p = k * n.factorization p := by rw [Nat.factorization_pow] rfl theorem Nat.Prime.factorization' {p : ℕ} (prime_p : p.Prime) : p.factorization p = 1 := by rw [prime_p.factorization] simp example {m n p : ℕ} (nnz : n ≠ 0) (prime_p : p.Prime) : m ^ 2 ≠ p * n ^ 2 := by intro sqr_eq have nsqr_nez : n ^ 2 ≠ 0 := by simpa have eq1 : Nat.factorization (m ^ 2) p = 2 * m.factorization p := by sorry have eq2 : (p * n ^ 2).factorization p = 2 * n.factorization p + 1 := by sorry have : 2 * m.factorization p % 2 = (2 * n.factorization p + 1) % 2 := by rw [← eq1, sqr_eq, eq2] rw [add_comm, Nat.add_mul_mod_self_left, Nat.mul_mod_right] at this norm_num at this example {m n k r : ℕ} (nnz : n ≠ 0) (pow_eq : m ^ k = r * n ^ k) {p : ℕ} (prime_p : p.Prime) : k ∣ r.factorization p := by cases' r with r · simp have npow_nz : n ^ k ≠ 0 := fun npowz => nnz (pow_eq_zero npowz) have eq1 : (m ^ k).factorization p = k * m.factorization p := by sorry have eq2 : (r.succ * n ^ k).factorization p = k * n.factorization p + r.succ.factorization p := by sorry have : r.succ.factorization p = k * m.factorization p - k * n.factorization p := by rw [← eq1, pow_eq, eq2, add_comm, Nat.add_sub_cancel] rw [this] sorry #check multiplicity
-
-
-
@@ -0,0 +1,147 @@import Mathlib.Data.Nat.GCD.Basic import Mathlib.Algebra.BigOperators.Basic import Mathlib.Tactic example (n : Nat) : n.succ ≠ Nat.zero := Nat.succ_ne_zero n example (m n : Nat) (h : m.succ = n.succ) : m = n := Nat.succ.inj h def fac : ℕ → ℕ | 0 => 1 | n + 1 => (n + 1) * fac n example : fac 0 = 1 := rfl example : fac 0 = 1 := by rw [fac] example : fac 0 = 1 := by simp [fac] example (n : ℕ) : fac (n + 1) = (n + 1) * fac n := rfl example (n : ℕ) : fac (n + 1) = (n + 1) * fac n := by rw [fac] example (n : ℕ) : fac (n + 1) = (n + 1) * fac n := by simp [fac] theorem fac_pos (n : ℕ) : 0 < fac n := by induction' n with n ih · rw [fac] exact zero_lt_one rw [fac] exact mul_pos n.succ_pos ih theorem dvd_fac {i n : ℕ} (ipos : 0 < i) (ile : i ≤ n) : i ∣ fac n := by induction' n with n ih · exact absurd ipos (not_lt_of_ge ile) rw [fac] cases' Nat.of_le_succ ile with h h · apply dvd_mul_of_dvd_right (ih h) rw [h] apply dvd_mul_right theorem pow_two_le_fac (n : ℕ) : 2 ^ (n - 1) ≤ fac n := by cases' n with n · simp [fac] sorry section variable {α : Type _} (s : Finset ℕ) (f : ℕ → ℕ) (n : ℕ) #check Finset.sum s f #check Finset.prod s f open BigOperators open Finset example : s.sum f = ∑ x in s, f x := rfl example : s.prod f = ∏ x in s, f x := rfl example : (range n).sum f = ∑ x in range n, f x := rfl example : (range n).prod f = ∏ x in range n, f x := rfl example (f : ℕ → ℕ) : (∑ x in range 0, f x) = 0 := Finset.sum_range_zero f example (f : ℕ → ℕ) (n : ℕ) : (∑ x in range n.succ, f x) = (∑ x in range n, f x) + f n := Finset.sum_range_succ f n example (f : ℕ → ℕ) : (∏ x in range 0, f x) = 1 := Finset.prod_range_zero f example (f : ℕ → ℕ) (n : ℕ) : (∏ x in range n.succ, f x) = (∏ x in range n, f x) * f n := Finset.prod_range_succ f n example (n : ℕ) : fac n = ∏ i in range n, (i + 1) := by induction' n with n ih · rw [fac, prod_range_zero] rw [fac, ih, prod_range_succ, mul_comm] example (a b c d e f : ℕ) : a * (b * c * f * (d * e)) = d * (a * f * e) * (c * b) := by simp [mul_assoc, mul_comm, mul_left_comm] theorem sum_id (n : ℕ) : (∑ i in range (n + 1), i) = n * (n + 1) / 2 := by symm; apply Nat.div_eq_of_eq_mul_right (by norm_num : 0 < 2) induction' n with n ih · simp rw [Finset.sum_range_succ, mul_add 2, ← ih, Nat.succ_eq_add_one] ring theorem sum_sqr (n : ℕ) : (∑ i in range (n + 1), i ^ 2) = n * (n + 1) * (2 * n + 1) / 6 := by sorry end inductive MyNat | zero : MyNat | succ : MyNat → MyNat namespace MyNat def add : MyNat → MyNat → MyNat | x, zero => x | x, succ y => succ (add x y) def mul : MyNat → MyNat → MyNat | x, zero => zero | x, succ y => add (mul x y) x theorem zero_add (n : MyNat) : add zero n = n := by induction' n with n ih · rfl rw [add, ih] theorem succ_add (m n : MyNat) : add (succ m) n = succ (add m n) := by induction' n with n ih · rfl rw [add, ih] rfl theorem add_comm (m n : MyNat) : add m n = add n m := by induction' n with n ih · rw [zero_add] rfl rw [add, succ_add, ih] theorem add_assoc (m n k : MyNat) : add (add m n) k = add m (add n k) := by sorry theorem mul_add (m n k : MyNat) : mul m (add n k) = add (mul m n) (mul m k) := by sorry theorem zero_mul (n : MyNat) : mul zero n = zero := by sorry theorem succ_mul (m n : MyNat) : mul (succ m) n = add (mul m n) n := by sorry theorem mul_comm (m n : MyNat) : mul m n = mul n m := by sorry end MyNat
-
-
-
@@ -0,0 +1,233 @@import Mathlib.Data.Nat.Prime import Mathlib.Algebra.BigOperators.Order import Mathlib.Tactic import Mathlib.Tactic.IntervalCases open BigOperators namespace C05S03 theorem two_le {m : ℕ} (h0 : m ≠ 0) (h1 : m ≠ 1) : 2 ≤ m := by cases m; contradiction case succ m => cases m; contradiction repeat' apply Nat.succ_le_succ apply zero_le example {m : ℕ} (h0 : m ≠ 0) (h1 : m ≠ 1) : 2 ≤ m := by by_contra h push_neg at h interval_cases m <;> contradiction example {m : ℕ} (h0 : m ≠ 0) (h1 : m ≠ 1) : 2 ≤ m := by by_contra h push_neg at h revert h0 h1 revert h m decide theorem exists_prime_factor {n : Nat} (h : 2 ≤ n) : ∃ p : Nat, p.Prime ∧ p ∣ n := by by_cases np : n.Prime · use n, np induction' n using Nat.strong_induction_on with n ih dsimp at ih rw [Nat.prime_def_lt] at np push_neg at np rcases np h with ⟨m, mltn, mdvdn, mne1⟩ have : m ≠ 0 := by intro mz rw [mz, zero_dvd_iff] at mdvdn linarith have mgt2 : 2 ≤ m := two_le this mne1 by_cases mp : m.Prime · use m, mp exact mdvdn . rcases ih m mltn mgt2 mp with ⟨p, pp, pdvd⟩ use p, pp apply pdvd.trans mdvdn theorem primes_infinite : ∀ n, ∃ p > n, Nat.Prime p := by intro n have : 2 ≤ Nat.factorial (n + 1) + 1 := by sorry rcases exists_prime_factor this with ⟨p, pp, pdvd⟩ refine' ⟨p, _, pp⟩ show p > n by_contra ple push_neg at ple have : p ∣ Nat.factorial (n + 1) := by sorry have : p ∣ 1 := by sorry show False sorry open Finset section variable {α : Type _} [DecidableEq α] (r s t : Finset α) example : r ∩ (s ∪ t) ⊆ r ∩ s ∪ r ∩ t := by rw [subset_iff] intro x rw [mem_inter, mem_union, mem_union, mem_inter, mem_inter] tauto example : r ∩ (s ∪ t) ⊆ r ∩ s ∪ r ∩ t := by simp [subset_iff] intro x tauto example : r ∩ s ∪ r ∩ t ⊆ r ∩ (s ∪ t) := by simp [subset_iff] intro x tauto example : r ∩ s ∪ r ∩ t = r ∩ (s ∪ t) := by ext x simp tauto end section variable {α : Type _} [DecidableEq α] (r s t : Finset α) example : (r ∪ s) ∩ (r ∪ t) = r ∪ s ∩ t := by sorry example : (r \ s) \ t = r \ (s ∪ t) := by sorry end example (s : Finset ℕ) (n : ℕ) (h : n ∈ s) : n ∣ ∏ i in s, i := Finset.dvd_prod_of_mem _ h theorem _root_.Nat.Prime.eq_of_dvd_of_prime {p q : ℕ} (prime_p : Nat.Prime p) (prime_q : Nat.Prime q) (h : p ∣ q) : p = q := by sorry theorem mem_of_dvd_prod_primes {s : Finset ℕ} {p : ℕ} (prime_p : p.Prime) : (∀ n ∈ s, Nat.Prime n) → (p ∣ ∏ n in s, n) → p ∈ s := by intro h₀ h₁ induction' s using Finset.induction_on with a s ans ih · simp at h₁ linarith [prime_p.two_le] simp [Finset.prod_insert ans, prime_p.dvd_mul] at h₀ h₁ rw [mem_insert] sorry example (s : Finset ℕ) (x : ℕ) : x ∈ s.filter Nat.Prime ↔ x ∈ s ∧ x.Prime := mem_filter theorem primes_infinite' : ∀ s : Finset Nat, ∃ p, Nat.Prime p ∧ p ∉ s := by intro s by_contra h push_neg at h set s' := s.filter Nat.Prime with s'_def have mem_s' : ∀ {n : ℕ}, n ∈ s' ↔ n.Prime := by intro n simp [s'_def] apply h have : 2 ≤ (∏ i in s', i) + 1 := by sorry rcases exists_prime_factor this with ⟨p, pp, pdvd⟩ have : p ∣ ∏ i in s', i := by sorry have : p ∣ 1 := by convert Nat.dvd_sub' pdvd this simp show False sorry theorem bounded_of_ex_finset (Q : ℕ → Prop) : (∃ s : Finset ℕ, ∀ k, Q k → k ∈ s) → ∃ n, ∀ k, Q k → k < n := by rintro ⟨s, hs⟩ use s.sup id + 1 intro k Qk apply Nat.lt_succ_of_le show id k ≤ s.sup id apply le_sup (hs k Qk) theorem ex_finset_of_bounded (Q : ℕ → Prop) [DecidablePred Q] : (∃ n, ∀ k, Q k → k ≤ n) → ∃ s : Finset ℕ, ∀ k, Q k ↔ k ∈ s := by rintro ⟨n, hn⟩ use (range (n + 1)).filter Q intro k simp [Nat.lt_succ_iff] exact hn k example : 27 % 4 = 3 := by norm_num example (n : ℕ) : (4 * n + 3) % 4 = 3 := by rw [add_comm, Nat.add_mul_mod_self_left] norm_num theorem mod_4_eq_3_or_mod_4_eq_3 {m n : ℕ} (h : m * n % 4 = 3) : m % 4 = 3 ∨ n % 4 = 3 := by revert h rw [Nat.mul_mod] have : m % 4 < 4 := Nat.mod_lt m (by norm_num) interval_cases hm : m % 4 <;> simp [hm] have : n % 4 < 4 := Nat.mod_lt n (by norm_num) interval_cases hn : n % 4 <;> simp [hn] theorem two_le_of_mod_4_eq_3 {n : ℕ} (h : n % 4 = 3) : 2 ≤ n := by apply two_le <;> · intro neq rw [neq] at h norm_num at h theorem aux {m n : ℕ} (h₀ : m ∣ n) (h₁ : 2 ≤ m) (h₂ : m < n) : n / m ∣ n ∧ n / m < n := by sorry theorem exists_prime_factor_mod_4_eq_3 {n : Nat} (h : n % 4 = 3) : ∃ p : Nat, p.Prime ∧ p ∣ n ∧ p % 4 = 3 := by by_cases np : n.Prime · use n exact ⟨np, dvd_rfl, h⟩ induction' n using Nat.strong_induction_on with n ih dsimp at ih rw [Nat.prime_def_lt] at np push_neg at np rcases np (two_le_of_mod_4_eq_3 h) with ⟨m, mltn, mdvdn, mne1⟩ have mge2 : 2 ≤ m := by apply two_le _ mne1 intro mz rw [mz, zero_dvd_iff] at mdvdn linarith have neq : m * (n / m) = n := Nat.mul_div_cancel' mdvdn have : m % 4 = 3 ∨ n / m % 4 = 3 := by apply mod_4_eq_3_or_mod_4_eq_3 rw [neq, h] cases' this with h1 h1 . sorry . sorry example (m n : ℕ) (s : Finset ℕ) (h : m ∈ erase s n) : m ≠ n ∧ m ∈ s := by rwa [mem_erase] at h example (m n : ℕ) (s : Finset ℕ) (h : m ∈ erase s n) : m ≠ n ∧ m ∈ s := by simp at h assumption theorem primes_mod_4_eq_3_infinite : ∀ n, ∃ p > n, Nat.Prime p ∧ p % 4 = 3 := by by_contra h push_neg at h cases' h with n hn have : ∃ s : Finset Nat, ∀ p : ℕ, p.Prime ∧ p % 4 = 3 ↔ p ∈ s := by apply ex_finset_of_bounded use n contrapose! hn rcases hn with ⟨p, ⟨pp, p4⟩, pltn⟩ exact ⟨p, pltn, pp, p4⟩ cases' this with s hs have h₁ : ((4 * ∏ i in erase s 3, i) + 3) % 4 = 3 := by sorry rcases exists_prime_factor_mod_4_eq_3 h₁ with ⟨p, pp, pdvd, p4eq⟩ have ps : p ∈ s := by sorry have pne3 : p ≠ 3 := by sorry have : p ∣ 4 * ∏ i in erase s 3, i := by sorry have : p ∣ 3 := by sorry have : p = 3 := by sorry contradiction
-
-
-
@@ -0,0 +1,105 @@import Mathlib.Data.Nat.Factorization.Basic import Mathlib.Data.Nat.Prime import Mathlib.Tactic.NormNum.GCD import Mathlib.Tactic.NormNum.Prime theorem even_of_even_sqr {m : ℕ} (h : 2 ∣ m ^ 2) : 2 ∣ m := by rw [pow_two, Nat.prime_two.dvd_mul] at h cases h <;> assumption example {m n : ℕ} (coprime_mn : m.coprime n) : m ^ 2 ≠ 2 * n ^ 2 := by intro sqr_eq have : 2 ∣ m := by apply even_of_even_sqr rw [sqr_eq] apply dvd_mul_right obtain ⟨k, meq⟩ := dvd_iff_exists_eq_mul_left.mp this have : 2 * (2 * k ^ 2) = 2 * n ^ 2 := by rw [← sqr_eq, meq] ring have : 2 * k ^ 2 = n ^ 2 := (mul_right_inj' (by norm_num)).mp this have : 2 ∣ n := by apply even_of_even_sqr rw [← this] apply dvd_mul_right have : 2 ∣ m.gcd n := by apply Nat.dvd_gcd <;> assumption have : 2 ∣ 1 := by convert this symm exact coprime_mn norm_num at this example {m n p : ℕ} (coprime_mn : m.coprime n) (prime_p : p.Prime) : m ^ 2 ≠ p * n ^ 2 := by intro sqr_eq have : p ∣ m := by apply prime_p.dvd_of_dvd_pow rw [sqr_eq] apply dvd_mul_right obtain ⟨k, meq⟩ := dvd_iff_exists_eq_mul_left.mp this have : p * (p * k ^ 2) = p * n ^ 2 := by rw [← sqr_eq, meq] ring have : p * k ^ 2 = n ^ 2 := by apply (mul_right_inj' _).mp this exact prime_p.ne_zero have : p ∣ n := by apply prime_p.dvd_of_dvd_pow rw [← this] apply dvd_mul_right have : p ∣ Nat.gcd m n := by apply Nat.dvd_gcd <;> assumption have : p ∣ 1 := by convert this symm exact coprime_mn have : 2 ≤ 1 := by apply prime_p.two_le.trans exact Nat.le_of_dvd zero_lt_one this norm_num at this theorem factorization_mul' {m n : ℕ} (mnez : m ≠ 0) (nnez : n ≠ 0) (p : ℕ) : (m * n).factorization p = m.factorization p + n.factorization p := by rw [Nat.factorization_mul mnez nnez] rfl theorem factorization_pow' (n k p : ℕ) : (n ^ k).factorization p = k * n.factorization p := by rw [Nat.factorization_pow] rfl theorem Nat.Prime.factorization' {p : ℕ} (prime_p : p.Prime) : p.factorization p = 1 := by rw [prime_p.factorization] simp example {m n p : ℕ} (nnz : n ≠ 0) (prime_p : p.Prime) : m ^ 2 ≠ p * n ^ 2 := by intro sqr_eq have nsqr_nez : n ^ 2 ≠ 0 := by simpa have eq1 : Nat.factorization (m ^ 2) p = 2 * m.factorization p := by rw [factorization_pow'] have eq2 : (p * n ^ 2).factorization p = 2 * n.factorization p + 1 := by rw [factorization_mul' prime_p.ne_zero nsqr_nez, prime_p.factorization', factorization_pow', add_comm] have : 2 * m.factorization p % 2 = (2 * n.factorization p + 1) % 2 := by rw [← eq1, sqr_eq, eq2] rw [add_comm, Nat.add_mul_mod_self_left, Nat.mul_mod_right] at this norm_num at this example {m n k r : ℕ} (nnz : n ≠ 0) (pow_eq : m ^ k = r * n ^ k) {p : ℕ} (prime_p : p.Prime) : k ∣ r.factorization p := by cases' r with r · simp have npow_nz : n ^ k ≠ 0 := fun npowz => nnz (pow_eq_zero npowz) have eq1 : (m ^ k).factorization p = k * m.factorization p := by rw [factorization_pow'] have eq2 : (r.succ * n ^ k).factorization p = k * n.factorization p + r.succ.factorization p := by rw [factorization_mul' r.succ_ne_zero npow_nz, factorization_pow', add_comm] have : r.succ.factorization p = k * m.factorization p - k * n.factorization p := by rw [← eq1, pow_eq, eq2, add_comm, Nat.add_sub_cancel] rw [this] apply Nat.dvd_sub' <;> apply Nat.dvd_mul_right
-
-
-
@@ -0,0 +1,97 @@import Mathlib.Data.Nat.GCD.Basic import Mathlib.Algebra.BigOperators.Basic import Mathlib.Tactic def fac : ℕ → ℕ | 0 => 1 | n + 1 => (n + 1) * fac n theorem pow_two_le_fac (n : ℕ) : 2 ^ (n - 1) ≤ fac n := by cases' n with n · simp [fac] induction' n with n ih · simp [fac] simp at * rw [pow_succ, fac] apply Nat.mul_le_mul _ ih repeat' apply Nat.succ_le_succ apply zero_le section variable {α : Type _} (s : Finset ℕ) (f : ℕ → ℕ) (n : ℕ) open BigOperators open Finset theorem sum_sqr (n : ℕ) : (∑ i in range (n + 1), i ^ 2) = n * (n + 1) * (2 * n + 1) / 6 := by symm; apply Nat.div_eq_of_eq_mul_right (by norm_num : 0 < 6) induction' n with n ih · simp rw [Finset.sum_range_succ, mul_add 6, ← ih, Nat.succ_eq_add_one] ring end inductive MyNat | zero : MyNat | succ : MyNat → MyNat namespace MyNat def add : MyNat → MyNat → MyNat | x, zero => x | x, succ y => succ (add x y) def mul : MyNat → MyNat → MyNat | x, zero => zero | x, succ y => add (mul x y) x theorem zero_add (n : MyNat) : add zero n = n := by induction' n with n ih · rfl rw [add, ih] theorem succ_add (m n : MyNat) : add (succ m) n = succ (add m n) := by induction' n with n ih · rfl rw [add, ih] rfl theorem add_comm (m n : MyNat) : add m n = add n m := by induction' n with n ih · rw [zero_add] rfl rw [add, succ_add, ih] theorem add_assoc (m n k : MyNat) : add (add m n) k = add m (add n k) := by induction' k with k ih · rfl rw [add, ih] rfl theorem mul_add (m n k : MyNat) : mul m (add n k) = add (mul m n) (mul m k) := by induction' k with k ih · rfl rw [add, mul, mul, ih, add_assoc] theorem zero_mul (n : MyNat) : mul zero n = zero := by induction' n with n ih · rfl rw [mul, ih] rfl theorem succ_mul (m n : MyNat) : mul (succ m) n = add (mul m n) n := by induction' n with n ih · rfl rw [mul, mul, ih, add_assoc, add_assoc, add_comm n, succ_add] rfl theorem mul_comm (m n : MyNat) : mul m n = mul n m := by induction' n with n ih · rw [zero_mul] rfl rw [mul, ih, succ_mul] end MyNat
-
-
-
@@ -0,0 +1,242 @@import Mathlib.Data.Nat.Prime import Mathlib.Algebra.BigOperators.Order import Mathlib.Tactic import Mathlib.Tactic.IntervalCases open BigOperators namespace C05S03 theorem two_le {m : ℕ} (h0 : m ≠ 0) (h1 : m ≠ 1) : 2 ≤ m := by cases m; contradiction case succ m => cases m; contradiction repeat' apply Nat.succ_le_succ apply zero_le theorem exists_prime_factor {n : Nat} (h : 2 ≤ n) : ∃ p : Nat, p.Prime ∧ p ∣ n := by by_cases np : n.Prime · use n, np induction' n using Nat.strong_induction_on with n ih dsimp at ih rw [Nat.prime_def_lt] at np push_neg at np rcases np h with ⟨m, mltn, mdvdn, mne1⟩ have : m ≠ 0 := by intro mz rw [mz, zero_dvd_iff] at mdvdn linarith have mgt2 : 2 ≤ m := two_le this mne1 by_cases mp : m.Prime · use m, mp exact mdvdn . rcases ih m mltn mgt2 mp with ⟨p, pp, pdvd⟩ use p, pp apply pdvd.trans mdvdn theorem primes_infinite : ∀ n, ∃ p > n, Nat.Prime p := by intro n have : 2 ≤ Nat.factorial (n + 1) + 1 := by apply Nat.succ_le_succ exact Nat.succ_le_of_lt (Nat.factorial_pos _) rcases exists_prime_factor this with ⟨p, pp, pdvd⟩ refine' ⟨p, _, pp⟩ show p > n by_contra ple push_neg at ple have : p ∣ Nat.factorial (n + 1) := by apply Nat.dvd_factorial apply pp.pos linarith have : p ∣ 1 := by convert Nat.dvd_sub' pdvd this simp show False have := Nat.le_of_dvd zero_lt_one this linarith [pp.two_le] open Finset section variable {α : Type _} [DecidableEq α] (r s t : Finset α) example : (r ∪ s) ∩ (r ∪ t) = r ∪ s ∩ t := by ext x rw [mem_inter, mem_union, mem_union, mem_union, mem_inter] tauto example : (r ∪ s) ∩ (r ∪ t) = r ∪ s ∩ t := by ext x simp tauto example : (r \ s) \ t = r \ (s ∪ t) := by ext x rw [mem_sdiff, mem_sdiff, mem_sdiff, mem_union] tauto example : (r \ s) \ t = r \ (s ∪ t) := by ext x simp tauto end theorem _root_.Nat.Prime.eq_of_dvd_of_prime {p q : ℕ} (prime_p : Nat.Prime p) (prime_q : Nat.Prime q) (h : p ∣ q) : p = q := by cases prime_q.eq_one_or_self_of_dvd _ h · linarith [prime_p.two_le] assumption theorem mem_of_dvd_prod_primes {s : Finset ℕ} {p : ℕ} (prime_p : p.Prime) : (∀ n ∈ s, Nat.Prime n) → (p ∣ ∏ n in s, n) → p ∈ s := by intro h₀ h₁ induction' s using Finset.induction_on with a s ans ih · simp at h₁ linarith [prime_p.two_le] simp [Finset.prod_insert ans, prime_p.dvd_mul] at h₀ h₁ rw [mem_insert] cases' h₁ with h₁ h₁ · left exact prime_p.eq_of_dvd_of_prime h₀.1 h₁ right exact ih h₀.2 h₁ theorem primes_infinite' : ∀ s : Finset Nat, ∃ p, Nat.Prime p ∧ p ∉ s := by intro s by_contra h push_neg at h set s' := s.filter Nat.Prime with s'_def have mem_s' : ∀ {n : ℕ}, n ∈ s' ↔ n.Prime := by intro n simp [s'_def] apply h have : 2 ≤ (∏ i in s', i) + 1 := by apply Nat.succ_le_succ apply Nat.succ_le_of_lt apply Finset.prod_pos intro n ns' apply (mem_s'.mp ns').pos rcases exists_prime_factor this with ⟨p, pp, pdvd⟩ have : p ∣ ∏ i in s', i := by apply dvd_prod_of_mem rw [mem_s'] apply pp have : p ∣ 1 := by convert Nat.dvd_sub' pdvd this simp show False have := Nat.le_of_dvd zero_lt_one this linarith [pp.two_le] theorem bounded_of_ex_finset (Q : ℕ → Prop) : (∃ s : Finset ℕ, ∀ k, Q k → k ∈ s) → ∃ n, ∀ k, Q k → k < n := by rintro ⟨s, hs⟩ use s.sup id + 1 intro k Qk apply Nat.lt_succ_of_le show id k ≤ s.sup id apply le_sup (hs k Qk) theorem ex_finset_of_bounded (Q : ℕ → Prop) [DecidablePred Q] : (∃ n, ∀ k, Q k → k ≤ n) → ∃ s : Finset ℕ, ∀ k, Q k ↔ k ∈ s := by rintro ⟨n, hn⟩ use (range (n + 1)).filter Q intro k simp [Nat.lt_succ_iff] exact hn k theorem mod_4_eq_3_or_mod_4_eq_3 {m n : ℕ} (h : m * n % 4 = 3) : m % 4 = 3 ∨ n % 4 = 3 := by revert h rw [Nat.mul_mod] have : m % 4 < 4 := Nat.mod_lt m (by norm_num) interval_cases hm : m % 4 <;> simp [hm] have : n % 4 < 4 := Nat.mod_lt n (by norm_num) interval_cases hn : n % 4 <;> simp [hn] theorem two_le_of_mod_4_eq_3 {n : ℕ} (h : n % 4 = 3) : 2 ≤ n := by apply two_le <;> · intro neq rw [neq] at h norm_num at h theorem aux {m n : ℕ} (h₀ : m ∣ n) (h₁ : 2 ≤ m) (h₂ : m < n) : n / m ∣ n ∧ n / m < n := by constructor · exact Nat.div_dvd_of_dvd h₀ exact Nat.div_lt_self (lt_of_le_of_lt (zero_le _) h₂) h₁ theorem exists_prime_factor_mod_4_eq_3 {n : Nat} (h : n % 4 = 3) : ∃ p : Nat, p.Prime ∧ p ∣ n ∧ p % 4 = 3 := by by_cases np : n.Prime · use n exact ⟨np, dvd_rfl, h⟩ induction' n using Nat.strong_induction_on with n ih dsimp at ih rw [Nat.prime_def_lt] at np push_neg at np rcases np (two_le_of_mod_4_eq_3 h) with ⟨m, mltn, mdvdn, mne1⟩ have mge2 : 2 ≤ m := by apply two_le _ mne1 intro mz rw [mz, zero_dvd_iff] at mdvdn linarith have neq : m * (n / m) = n := Nat.mul_div_cancel' mdvdn have : m % 4 = 3 ∨ n / m % 4 = 3 := by apply mod_4_eq_3_or_mod_4_eq_3 rw [neq, h] cases' this with h1 h1 · by_cases mp : m.Prime · use m exact ⟨mp, mdvdn, h1⟩ rcases ih m mltn h1 mp with ⟨p, pp, pdvd, p4eq⟩ use p exact ⟨pp, pdvd.trans mdvdn, p4eq⟩ obtain ⟨nmdvdn, nmltn⟩ := aux mdvdn mge2 mltn by_cases nmp : (n / m).Prime · use n / m exact ⟨nmp, nmdvdn, h1⟩ rcases ih (n / m) nmltn h1 nmp with ⟨p, pp, pdvd, p4eq⟩ use p exact ⟨pp, pdvd.trans nmdvdn, p4eq⟩ theorem primes_mod_4_eq_3_infinite : ∀ n, ∃ p > n, Nat.Prime p ∧ p % 4 = 3 := by by_contra h push_neg at h cases' h with n hn have : ∃ s : Finset Nat, ∀ p : ℕ, p.Prime ∧ p % 4 = 3 ↔ p ∈ s := by apply ex_finset_of_bounded use n contrapose! hn rcases hn with ⟨p, ⟨pp, p4⟩, pltn⟩ exact ⟨p, pltn, pp, p4⟩ cases' this with s hs have h₁ : ((4 * ∏ i in erase s 3, i) + 3) % 4 = 3 := by rw [add_comm, Nat.add_mul_mod_self_left] norm_num rcases exists_prime_factor_mod_4_eq_3 h₁ with ⟨p, pp, pdvd, p4eq⟩ have ps : p ∈ s := by rw [← hs p] exact ⟨pp, p4eq⟩ have pne3 : p ≠ 3 := by intro peq rw [peq, ← Nat.dvd_add_iff_left (dvd_refl 3)] at pdvd rw [Nat.prime_three.dvd_mul] at pdvd norm_num at pdvd have : 3 ∈ s.erase 3 := by apply mem_of_dvd_prod_primes Nat.prime_three _ pdvd intro n simp [← hs n] tauto simp at this have : p ∣ 4 * ∏ i in erase s 3, i := by apply dvd_trans _ (dvd_mul_left _ _) apply dvd_prod_of_mem simp constructor <;> assumption have : p ∣ 3 := by convert Nat.dvd_sub' pdvd this simp have : p = 3 := by apply pp.eq_of_dvd_of_prime Nat.prime_three this contradiction
-
-
-
@@ -0,0 +1,224 @@import Mathlib.Algebra.BigOperators.Ring import Mathlib.Data.Real.Basic namespace C06S01 noncomputable section @[ext] structure Point where x : ℝ y : ℝ z : ℝ #check Point.ext example (a b : Point) (hx : a.x = b.x) (hy : a.y = b.y) (hz : a.z = b.z) : a = b := by ext repeat' assumption def myPoint1 : Point where x := 2 y := -1 z := 4 def myPoint2 : Point := ⟨2, -1, 4⟩ def myPoint3 := Point.mk 2 (-1) 4 structure Point' where build :: x : ℝ y : ℝ z : ℝ #check Point'.build 2 (-1) 4 namespace Point def add (a b : Point) : Point := ⟨a.x + b.x, a.y + b.y, a.z + b.z⟩ def add' (a b : Point) : Point where x := a.x + b.x y := a.y + b.y z := a.z + b.z #check add myPoint1 myPoint2 #check myPoint1.add myPoint2 end Point #check Point.add myPoint1 myPoint2 #check myPoint1.add myPoint2 namespace Point protected theorem add_comm (a b : Point) : add a b = add b a := by rw [add, add] ext <;> dsimp repeat' apply add_comm example (a b : Point) : add a b = add b a := by simp [add, add_comm] theorem add_x (a b : Point) : (a.add b).x = a.x + b.x := rfl def addAlt : Point → Point → Point | Point.mk x₁ y₁ z₁, Point.mk x₂ y₂ z₂ => ⟨x₁ + x₂, y₁ + y₂, z₁ + z₂⟩ def addAlt' : Point → Point → Point | ⟨x₁, y₁, z₁⟩, ⟨x₂, y₂, z₂⟩ => ⟨x₁ + x₂, y₁ + y₂, z₁ + z₂⟩ theorem addAlt_x (a b : Point) : (a.addAlt b).x = a.x + b.x := by cases a cases b rfl theorem addAlt_comm (a b : Point) : addAlt a b = addAlt b a := by rcases a with ⟨xa, ya, za⟩ rcases b with ⟨xb, yb, zb⟩ rw [addAlt, addAlt] ext <;> dsimp apply add_comm repeat' apply add_comm example (a b : Point) : addAlt a b = addAlt b a := by rcases a with ⟨xa, ya, za⟩ rcases b with ⟨xb, yb, zb⟩ simp [addAlt, add_comm] example : ∀ a b : Point, addAlt a b = addAlt b a := by rintro ⟨xa, ya, za⟩ ⟨xb, yb, zb⟩ simp [addAlt, add_comm] example : ∀ a b : Point, add a b = add b a := fun ⟨xa, ya, za⟩ ⟨xb, yb, zb⟩ => by simp [add, add_comm] protected theorem add_assoc (a b c : Point) : (a.add b).add c = a.add (b.add c) := by sorry def smul (r : ℝ) (a : Point) : Point := sorry theorem smul_distrib (r : ℝ) (a b : Point) : (smul r a).add (smul r b) = smul r (a.add b) := by sorry end Point structure StandardTwoSimplex where x : ℝ y : ℝ z : ℝ x_nonneg : 0 ≤ x y_nonneg : 0 ≤ y z_nonneg : 0 ≤ z sum_eq : x + y + z = 1 namespace StandardTwoSimplex def swapXy (a : StandardTwoSimplex) : StandardTwoSimplex where x := a.y y := a.x z := a.z x_nonneg := a.y_nonneg y_nonneg := a.x_nonneg z_nonneg := a.z_nonneg sum_eq := by rw [add_comm a.y a.x, a.sum_eq] noncomputable section def midpoint (a b : StandardTwoSimplex) : StandardTwoSimplex where x := (a.x + b.x) / 2 y := (a.y + b.y) / 2 z := (a.z + b.z) / 2 x_nonneg := div_nonneg (add_nonneg a.x_nonneg b.x_nonneg) (by norm_num) y_nonneg := div_nonneg (add_nonneg a.y_nonneg b.y_nonneg) (by norm_num) z_nonneg := div_nonneg (add_nonneg a.z_nonneg b.z_nonneg) (by norm_num) sum_eq := by field_simp; linarith [a.sum_eq, b.sum_eq] def weightedAverage (lambda : Real) (lambda_nonneg : 0 ≤ lambda) (lambda_le : lambda ≤ 1) (a b : StandardTwoSimplex) : StandardTwoSimplex := sorry end end StandardTwoSimplex open BigOperators structure StandardSimplex (n : ℕ) where V : Fin n → ℝ NonNeg : ∀ i : Fin n, 0 ≤ V i sum_eq_one : (∑ i, V i) = 1 namespace StandardSimplex def midpoint (n : ℕ) (a b : StandardSimplex n) : StandardSimplex n where V i := (a.V i + b.V i) / 2 NonNeg := by intro i apply div_nonneg · linarith [a.NonNeg i, b.NonNeg i] norm_num sum_eq_one := by simp [div_eq_mul_inv, ← Finset.sum_mul, Finset.sum_add_distrib, a.sum_eq_one, b.sum_eq_one] field_simp end StandardSimplex structure IsLinear (f : ℝ → ℝ) where is_additive : ∀ x y, f (x + y) = f x + f y preserves_mul : ∀ x c, f (c * x) = c * f x section variable (f : ℝ → ℝ) (linf : IsLinear f) #check linf.is_additive #check linf.preserves_mul end def Point'' := ℝ × ℝ × ℝ def IsLinear' (f : ℝ → ℝ) := (∀ x y, f (x + y) = f x + f y) ∧ ∀ x c, f (c * x) = c * f x def PReal := { y : ℝ // 0 < y } section variable (x : PReal) #check x.val #check x.property #check x.1 #check x.2 end def StandardTwoSimplex' := { p : ℝ × ℝ × ℝ // 0 ≤ p.1 ∧ 0 ≤ p.2.1 ∧ 0 ≤ p.2.2 ∧ p.1 + p.2.1 + p.2.2 = 1 } def StandardSimplex' (n : ℕ) := { v : Fin n → ℝ // (∀ i : Fin n, 0 ≤ v i) ∧ (∑ i, v i) = 1 } def StdSimplex := Σ n : ℕ, StandardSimplex n section variable (s : StdSimplex) #check s.fst #check s.snd #check s.1 #check s.2 end
-
-
-
@@ -0,0 +1,171 @@import Mathlib.Data.Real.Basic namespace C06S02 structure Group₁ (α : Type _) where mul : α → α → α one : α inv : α → α mul_assoc : ∀ x y z : α, mul (mul x y) z = mul x (mul y z) mul_one : ∀ x : α, mul x one = x one_mul : ∀ x : α, mul one x = x mul_left_inv : ∀ x : α, mul (inv x) x = one structure Group₁Cat where α : Type _ str : Group₁ α section variable (α β γ : Type _) variable (f : α ≃ β) (g : β ≃ γ) #check Equiv α β #check (f.toFun : α → β) #check (f.invFun : β → α) #check (f.right_inv : ∀ x : β, f (f.invFun x) = x) #check (f.left_inv : ∀ x : α, f.invFun (f x) = x) #check (Equiv.refl α : α ≃ α) #check (f.symm : β ≃ α) #check (f.trans g : α ≃ γ) example (x : α) : (f.trans g).toFun x = g.toFun (f.toFun x) := rfl example (x : α) : (f.trans g) x = g (f x) := rfl example : (f.trans g : α → γ) = g ∘ f := rfl end example (α : Type _) : Equiv.Perm α = (α ≃ α) := rfl def permGroup {α : Type _} : Group₁ (Equiv.Perm α) where mul f g := Equiv.trans g f one := Equiv.refl α inv := Equiv.symm mul_assoc f g h := (Equiv.trans_assoc _ _ _).symm one_mul := Equiv.trans_refl mul_one := Equiv.refl_trans mul_left_inv := Equiv.self_trans_symm structure AddGroup₁ (α : Type _) where (add : α → α → α) -- fill in the rest @[ext] structure Point where x : ℝ y : ℝ z : ℝ namespace Point def add (a b : Point) : Point := ⟨a.x + b.x, a.y + b.y, a.z + b.z⟩ def neg (a : Point) : Point := sorry def zero : Point := sorry def add_group_point : AddGroup₁ point := sorry end Point section variable {α : Type _} (f g : Equiv.Perm α) (n : ℕ) #check f * g #check mul_assoc f g g⁻¹ -- group power, defined for any group #check g ^ n example : f * g * g⁻¹ = f := by rw [mul_assoc, mul_right_inv, mul_one] example : f * g * g⁻¹ = f := mul_inv_cancel_right f g example {α : Type _} (f g : Equiv.Perm α) : g.symm.trans (g.trans f) = f := mul_inv_cancel_right f g end class Group₂ (α : Type _) where mul : α → α → α one : α inv : α → α mul_assoc : ∀ x y z : α, mul (mul x y) z = mul x (mul y z) mul_one : ∀ x : α, mul x one = x one_mul : ∀ x : α, mul one x = x mul_left_inv : ∀ x : α, mul (inv x) x = one instance {α : Type _} : Group₂ (Equiv.Perm α) where mul f g := Equiv.trans g f one := Equiv.refl α inv := Equiv.symm mul_assoc f g h := (Equiv.trans_assoc _ _ _).symm one_mul := Equiv.trans_refl mul_one := Equiv.refl_trans mul_left_inv := Equiv.self_trans_symm #check @Group₂.mul def mySquare {α : Type _} [Group₂ α] (x : α) := Group₂.mul x x #check @mySquare section variable {β : Type _} (f g : Equiv.Perm β) example : Group₂.mul f g = g.trans f := rfl example : mySquare f = f.trans f := rfl end instance : Inhabited Point where default := ⟨0, 0, 0⟩ #check (default : Point) example : ([] : List Point).headI = default := rfl instance : Add Point where add := Point.add section variable (x y : Point) #check x + y example : x + y = Point.add x y := rfl end instance hasMulGroup₂ {α : Type _} [Group₂ α] : Mul α := ⟨Group₂.mul⟩ instance hasOneGroup₂ {α : Type _} [Group₂ α] : One α := ⟨Group₂.one⟩ instance hasInvGroup₂ {α : Type _} [Group₂ α] : Inv α := ⟨Group₂.inv⟩ section variable {α : Type _} (f g : Equiv.Perm α) #check f * 1 * g⁻¹ def foo : f * 1 * g⁻¹ = g.symm.trans ((Equiv.refl α).trans f) := rfl end class AddGroup₂ (α : Type _) where add : α → α → α -- fill in the rest
-
-
-
@@ -0,0 +1,276 @@import Mathlib.Data.Int.Basic import Mathlib.Algebra.EuclideanDomain.Basic import Mathlib.RingTheory.PrincipalIdealDomain import Mathlib.Tactic @[ext] structure gaussInt where re : ℤ im : ℤ namespace gaussInt instance : Zero gaussInt := ⟨⟨0, 0⟩⟩ instance : One gaussInt := ⟨⟨1, 0⟩⟩ instance : Add gaussInt := ⟨fun x y => ⟨x.re + y.re, x.im + y.im⟩⟩ instance : Neg gaussInt := ⟨fun x => ⟨-x.re, -x.im⟩⟩ instance : Mul gaussInt := ⟨fun x y => ⟨x.re * y.re - x.im * y.im, x.re * y.im + x.im * y.re⟩⟩ theorem zero_def : (0 : gaussInt) = ⟨0, 0⟩ := rfl theorem one_def : (1 : gaussInt) = ⟨1, 0⟩ := rfl theorem add_def (x y : gaussInt) : x + y = ⟨x.re + y.re, x.im + y.im⟩ := rfl theorem neg_def (x : gaussInt) : -x = ⟨-x.re, -x.im⟩ := rfl theorem mul_def (x y : gaussInt) : x * y = ⟨x.re * y.re - x.im * y.im, x.re * y.im + x.im * y.re⟩ := rfl @[simp] theorem zero_re : (0 : gaussInt).re = 0 := rfl @[simp] theorem zero_im : (0 : gaussInt).im = 0 := rfl @[simp] theorem one_re : (1 : gaussInt).re = 1 := rfl @[simp] theorem one_im : (1 : gaussInt).im = 0 := rfl @[simp] theorem add_re (x y : gaussInt) : (x + y).re = x.re + y.re := rfl @[simp] theorem add_im (x y : gaussInt) : (x + y).im = x.im + y.im := rfl @[simp] theorem neg_re (x : gaussInt) : (-x).re = -x.re := rfl @[simp] theorem neg_im (x : gaussInt) : (-x).im = -x.im := rfl @[simp] theorem mul_re (x y : gaussInt) : (x * y).re = x.re * y.re - x.im * y.im := rfl @[simp] theorem mul_im (x y : gaussInt) : (x * y).im = x.re * y.im + x.im * y.re := rfl instance instCommRing : CommRing gaussInt where zero := 0 one := 1 add := (· + ·) neg x := -x mul := (· * ·) add_assoc := by intros ext <;> simp <;> ring zero_add := by intro ext <;> simp add_zero := by intro ext <;> simp add_left_neg := by intro ext <;> simp add_comm := by intros ext <;> simp <;> ring mul_assoc := by intros ext <;> simp <;> ring one_mul := by intro ext <;> simp mul_one := by intro ext <;> simp left_distrib := by intros ext <;> simp <;> ring right_distrib := by intros ext <;> simp <;> ring mul_comm := by intros ext <;> simp <;> ring zero_mul := sorry mul_zero := sorry instance : Nontrivial gaussInt := by use 0, 1 rw [Ne, gaussInt.ext_iff] simp end gaussInt example (a b : ℤ) : a = b * (a / b) + a % b := Eq.symm <| Int.ediv_add_emod a b example (a b : ℤ) : b ≠ 0 → 0 ≤ a % b := Int.emod_nonneg a example (a b : ℤ) : b ≠ 0 → a % b < abs b := Int.emod_lt a namespace Int def div' (a b : ℤ) := (a + b / 2) / b def mod' (a b : ℤ) := (a + b / 2) % b - b / 2 theorem div'_add_mod' (a b : ℤ) : b * div' a b + mod' a b = a := by rw [div', mod'] linarith [Int.ediv_add_emod (a + b / 2) b] theorem abs_mod'_le (a b : ℤ) (h : 0 < b) : abs (mod' a b) ≤ b / 2 := by rw [mod', abs_le] constructor · linarith [Int.emod_nonneg (a + b / 2) h.ne'] have := Int.emod_lt_of_pos (a + b / 2) h have := Int.ediv_add_emod b 2 have := Int.emod_lt_of_pos b zero_lt_two revert this; intro this -- FIXME, this should not be needed linarith theorem mod'_eq (a b : ℤ) : mod' a b = a - b * div' a b := by linarith [div'_add_mod' a b] end Int theorem sq_add_sq_eq_zero {α : Type _} [LinearOrderedRing α] (x y : α) : x ^ 2 + y ^ 2 = 0 ↔ x = 0 ∧ y = 0 := by sorry namespace gaussInt def norm (x : gaussInt) := x.re ^ 2 + x.im ^ 2 @[simp] theorem norm_nonneg (x : gaussInt) : 0 ≤ norm x := by sorry theorem norm_eq_zero (x : gaussInt) : norm x = 0 ↔ x = 0 := by sorry theorem norm_pos (x : gaussInt) : 0 < norm x ↔ x ≠ 0 := by sorry theorem norm_mul (x y : gaussInt) : norm (x * y) = norm x * norm y := by sorry def conj (x : gaussInt) : gaussInt := ⟨x.re, -x.im⟩ @[simp] theorem conj_re (x : gaussInt) : (conj x).re = x.re := rfl @[simp] theorem conj_im (x : gaussInt) : (conj x).im = -x.im := rfl theorem norm_conj (x : gaussInt) : norm (conj x) = norm x := by simp [norm] instance : Div gaussInt := ⟨fun x y => ⟨Int.div' (x * conj y).re (norm y), Int.div' (x * conj y).im (norm y)⟩⟩ instance : Mod gaussInt := ⟨fun x y => x - y * (x / y)⟩ theorem div_def (x y : gaussInt) : x / y = ⟨Int.div' (x * conj y).re (norm y), Int.div' (x * conj y).im (norm y)⟩ := rfl theorem mod_def (x y : gaussInt) : x % y = x - y * (x / y) := rfl theorem norm_mod_lt (x : gaussInt) {y : gaussInt} (hy : y ≠ 0) : (x % y).norm < y.norm := by have norm_y_pos : 0 < norm y := by rwa [norm_pos] have : x % y * conj y = ⟨Int.mod' (x * conj y).re (norm y), Int.mod' (x * conj y).im (norm y)⟩ := by rw [mod_def, sub_mul, Int.mod'_eq, Int.mod'_eq, sub_eq_add_neg, div_def, norm] ext <;> simp <;> ring have : norm (x % y) * norm y ≤ norm y / 2 * norm y := by conv => lhs rw [← norm_conj y, ← norm_mul, this, norm] simp trans 2 * (y.norm / 2) ^ 2 · rw [two_mul] apply add_le_add <;> · rw [sq_le_sq] apply le_trans (Int.abs_mod'_le _ _ norm_y_pos) apply le_abs_self rw [pow_two, ← mul_assoc, mul_comm, mul_comm (2 : ℤ)] apply mul_le_mul_of_nonneg_left · apply Int.ediv_mul_le norm_num apply Int.ediv_nonneg (norm_nonneg y) norm_num have : norm (x % y) ≤ norm y / 2 := le_of_mul_le_mul_right this norm_y_pos apply lt_of_le_of_lt this apply Int.ediv_lt_of_lt_mul · norm_num linarith theorem coe_natAbs_norm (x : gaussInt) : (x.norm.natAbs : ℤ) = x.norm := Int.natAbs_of_nonneg (norm_nonneg _) theorem natAbs_norm_mod_lt (x y : gaussInt) (hy : y ≠ 0) : (x % y).norm.natAbs < y.norm.natAbs := by apply Int.ofNat_lt.1 simp only [Int.coe_natAbs, abs_of_nonneg, norm_nonneg] apply norm_mod_lt x hy theorem not_norm_mul_left_lt_norm (x : gaussInt) {y : gaussInt} (hy : y ≠ 0) : ¬(norm (x * y)).natAbs < (norm x).natAbs := by apply not_lt_of_ge rw [norm_mul, Int.natAbs_mul] apply le_mul_of_one_le_right (Nat.zero_le _) apply Int.ofNat_le.1 rw [coe_natAbs_norm] exact Int.add_one_le_of_lt ((norm_pos _).mpr hy) instance : EuclideanDomain gaussInt := { gaussInt.instCommRing with quotient := (· / ·) remainder := (· % ·) quotient_mul_add_remainder_eq := fun x y => by simp only; rw [mod_def, add_comm, sub_add_cancel] quotient_zero := fun x => by simp [div_def, norm, Int.div'] rfl r := Measure (Int.natAbs ∘ norm) r_wellFounded := (measure (Int.natAbs ∘ norm)).2 remainder_lt := natAbs_norm_mod_lt mul_left_not_lt := not_norm_mul_left_lt_norm } example (x : gaussInt) : Irreducible x ↔ Prime x := PrincipalIdealRing.irreducible_iff_prime end gaussInt
-
-
-
@@ -0,0 +1,99 @@import Mathlib.Algebra.BigOperators.Ring import Mathlib.Data.Real.Basic namespace C06S01 noncomputable section @[ext] structure Point where x : ℝ y : ℝ z : ℝ namespace Point def add (a b : Point) : Point := ⟨a.x + b.x, a.y + b.y, a.z + b.z⟩ protected theorem add_assoc (a b c : Point) : (a.add b).add c = a.add (b.add c) := by simp [add, add_assoc] def smul (r : ℝ) (a : Point) : Point := ⟨r * a.x, r * a.y, r * a.z⟩ theorem smul_distrib (r : ℝ) (a b : Point) : (smul r a).add (smul r b) = smul r (a.add b) := by simp [add, smul, mul_add] end Point structure StandardTwoSimplex where x : ℝ y : ℝ z : ℝ x_nonneg : 0 ≤ x y_nonneg : 0 ≤ y z_nonneg : 0 ≤ z sum_eq : x + y + z = 1 namespace StandardTwoSimplex noncomputable section def weightedAverage (lambda : Real) (lambda_nonneg : 0 ≤ lambda) (lambda_le : lambda ≤ 1) (a b : StandardTwoSimplex) : StandardTwoSimplex where x := lambda * a.x + (1 - lambda) * b.x y := lambda * a.y + (1 - lambda) * b.y z := lambda * a.z + (1 - lambda) * b.z x_nonneg := add_nonneg (mul_nonneg lambda_nonneg a.x_nonneg) (mul_nonneg (by linarith) b.x_nonneg) y_nonneg := add_nonneg (mul_nonneg lambda_nonneg a.y_nonneg) (mul_nonneg (by linarith) b.y_nonneg) z_nonneg := add_nonneg (mul_nonneg lambda_nonneg a.z_nonneg) (mul_nonneg (by linarith) b.z_nonneg) sum_eq := by trans (a.x + a.y + a.z) * lambda + (b.x + b.y + b.z) * (1 - lambda) · ring simp [a.sum_eq, b.sum_eq] end end StandardTwoSimplex open BigOperators structure StandardSimplex (n : ℕ) where V : Fin n → ℝ NonNeg : ∀ i : Fin n, 0 ≤ V i sum_eq_one : (∑ i, V i) = 1 namespace StandardSimplex def midpoint (n : ℕ) (a b : StandardSimplex n) : StandardSimplex n where V i := (a.V i + b.V i) / 2 NonNeg := by intro i apply div_nonneg · linarith [a.NonNeg i, b.NonNeg i] norm_num sum_eq_one := by simp [div_eq_mul_inv, ← Finset.sum_mul, Finset.sum_add_distrib, a.sum_eq_one, b.sum_eq_one] field_simp end StandardSimplex namespace StandardSimplex def weightedAverage {n : ℕ} (lambda : Real) (lambda_nonneg : 0 ≤ lambda) (lambda_le : lambda ≤ 1) (a b : StandardSimplex n) : StandardSimplex n where V i := lambda * a.V i + (1 - lambda) * b.V i NonNeg i := add_nonneg (mul_nonneg lambda_nonneg (a.NonNeg i)) (mul_nonneg (by linarith) (b.NonNeg i)) sum_eq_one := by trans (lambda * ∑ i, a.V i) + (1 - lambda) * ∑ i, b.V i · rw [Finset.sum_add_distrib, Finset.mul_sum, Finset.mul_sum] simp [a.sum_eq_one, b.sum_eq_one] end StandardSimplex
-
-
-
@@ -0,0 +1,74 @@import Mathlib.Data.Real.Basic namespace C06S02 structure AddGroup₁ (α : Type _) where add : α → α → α zero : α neg : α → α add_assoc : ∀ x y z : α, add (add x y) z = add x (add y z) add_zero : ∀ x : α, add x zero = x zero_add : ∀ x : α, add x zero = x add_left_neg : ∀ x : α, add (neg x) x = zero @[ext] structure Point where x : ℝ y : ℝ z : ℝ namespace Point def add (a b : Point) : Point := ⟨a.x + b.x, a.y + b.y, a.z + b.z⟩ def neg (a : Point) : Point := ⟨-a.x, -a.y, -a.z⟩ def zero : Point := ⟨0, 0, 0⟩ def addGroupPoint : AddGroup₁ Point where add := Point.add zero := Point.zero neg := Point.neg add_assoc := by simp [Point.add, add_assoc] add_zero := by simp [Point.add, Point.zero] zero_add := by simp [Point.add, Point.zero] add_left_neg := by simp [Point.add, Point.neg, Point.zero] end Point class AddGroup₂ (α : Type _) where add : α → α → α zero : α neg : α → α add_assoc : ∀ x y z : α, add (add x y) z = add x (add y z) add_zero : ∀ x : α, add x zero = x zero_add : ∀ x : α, add x zero = x add_left_neg : ∀ x : α, add (neg x) x = zero instance hasAddAddGroup₂ {α : Type _} [AddGroup₂ α] : Add α := ⟨AddGroup₂.add⟩ instance hasZeroAddGroup₂ {α : Type _} [AddGroup₂ α] : Zero α := ⟨AddGroup₂.zero⟩ instance hasNegAddGroup₂ {α : Type _} [AddGroup₂ α] : Neg α := ⟨AddGroup₂.neg⟩ instance : AddGroup₂ Point where add := Point.add zero := Point.zero neg := Point.neg add_assoc := by simp [Point.add, add_assoc] add_zero := by simp [Point.add, Point.zero] zero_add := by simp [Point.add, Point.zero] add_left_neg := by simp [Point.add, Point.neg, Point.zero] section variable (x y : Point) #check x + -y + 0 end
-
-
-
@@ -0,0 +1,290 @@import Mathlib.Data.Int.Basic import Mathlib.Algebra.EuclideanDomain.Basic import Mathlib.RingTheory.PrincipalIdealDomain import Mathlib.Tactic @[ext] structure gaussInt where re : ℤ im : ℤ namespace gaussInt instance : Zero gaussInt := ⟨⟨0, 0⟩⟩ instance : One gaussInt := ⟨⟨1, 0⟩⟩ instance : Add gaussInt := ⟨fun x y => ⟨x.re + y.re, x.im + y.im⟩⟩ instance : Neg gaussInt := ⟨fun x => ⟨-x.re, -x.im⟩⟩ instance : Mul gaussInt := ⟨fun x y => ⟨x.re * y.re - x.im * y.im, x.re * y.im + x.im * y.re⟩⟩ theorem zero_def : (0 : gaussInt) = ⟨0, 0⟩ := rfl theorem one_def : (1 : gaussInt) = ⟨1, 0⟩ := rfl theorem add_def (x y : gaussInt) : x + y = ⟨x.re + y.re, x.im + y.im⟩ := rfl theorem neg_def (x : gaussInt) : -x = ⟨-x.re, -x.im⟩ := rfl theorem mul_def (x y : gaussInt) : x * y = ⟨x.re * y.re - x.im * y.im, x.re * y.im + x.im * y.re⟩ := rfl @[simp] theorem zero_re : (0 : gaussInt).re = 0 := rfl @[simp] theorem zero_im : (0 : gaussInt).im = 0 := rfl @[simp] theorem one_re : (1 : gaussInt).re = 1 := rfl @[simp] theorem one_im : (1 : gaussInt).im = 0 := rfl @[simp] theorem add_re (x y : gaussInt) : (x + y).re = x.re + y.re := rfl @[simp] theorem add_im (x y : gaussInt) : (x + y).im = x.im + y.im := rfl @[simp] theorem neg_re (x : gaussInt) : (-x).re = -x.re := rfl @[simp] theorem neg_im (x : gaussInt) : (-x).im = -x.im := rfl @[simp] theorem mul_re (x y : gaussInt) : (x * y).re = x.re * y.re - x.im * y.im := rfl @[simp] theorem mul_im (x y : gaussInt) : (x * y).im = x.re * y.im + x.im * y.re := rfl instance instCommRing : CommRing gaussInt where zero := 0 one := 1 add := (· + ·) neg x := -x mul := (· * ·) add_assoc := by intros ext <;> simp <;> ring zero_add := by intro ext <;> simp add_zero := by intro ext <;> simp add_left_neg := by intro ext <;> simp add_comm := by intros ext <;> simp <;> ring mul_assoc := by intros ext <;> simp <;> ring one_mul := by intro ext <;> simp mul_one := by intro ext <;> simp left_distrib := by intros ext <;> simp <;> ring right_distrib := by intros ext <;> simp <;> ring mul_comm := by intros ext <;> simp <;> ring zero_mul := sorry mul_zero := sorry instance : Nontrivial gaussInt := by use 0, 1 rw [Ne, gaussInt.ext_iff] simp end gaussInt namespace Int def div' (a b : ℤ) := (a + b / 2) / b def mod' (a b : ℤ) := (a + b / 2) % b - b / 2 theorem div'_add_mod' (a b : ℤ) : b * div' a b + mod' a b = a := by rw [div', mod'] linarith [Int.ediv_add_emod (a + b / 2) b] theorem abs_mod'_le (a b : ℤ) (h : 0 < b) : abs (mod' a b) ≤ b / 2 := by rw [mod', abs_le] constructor · linarith [Int.emod_nonneg (a + b / 2) h.ne'] have := Int.emod_lt_of_pos (a + b / 2) h have := Int.ediv_add_emod b 2 have := Int.emod_lt_of_pos b zero_lt_two revert this; intro this -- FIXME, this should not be needed linarith theorem mod'_eq (a b : ℤ) : mod' a b = a - b * div' a b := by linarith [div'_add_mod' a b] end Int private theorem aux {α : Type _} [LinearOrderedRing α] {x y : α} (h : x ^ 2 + y ^ 2 = 0) : x = 0 := haveI h' : x ^ 2 = 0 := by apply le_antisymm _ (sq_nonneg x) rw [← h] apply le_add_of_nonneg_right (sq_nonneg y) pow_eq_zero h' theorem sq_add_sq_eq_zero {α : Type _} [LinearOrderedRing α] (x y : α) : x ^ 2 + y ^ 2 = 0 ↔ x = 0 ∧ y = 0 := by constructor · intro h constructor · exact aux h rw [add_comm] at h exact aux h rintro ⟨rfl, rfl⟩ norm_num namespace gaussInt def norm (x : gaussInt) := x.re ^ 2 + x.im ^ 2 @[simp] theorem norm_nonneg (x : gaussInt) : 0 ≤ norm x := by apply add_nonneg <;> apply sq_nonneg theorem norm_eq_zero (x : gaussInt) : norm x = 0 ↔ x = 0 := by rw [norm, sq_add_sq_eq_zero, gaussInt.ext_iff] rfl theorem norm_pos (x : gaussInt) : 0 < norm x ↔ x ≠ 0 := by rw [lt_iff_le_and_ne, ne_comm, Ne, norm_eq_zero] simp [norm_nonneg] theorem norm_mul (x y : gaussInt) : norm (x * y) = norm x * norm y := by simp [norm] ring def conj (x : gaussInt) : gaussInt := ⟨x.re, -x.im⟩ @[simp] theorem conj_re (x : gaussInt) : (conj x).re = x.re := rfl @[simp] theorem conj_im (x : gaussInt) : (conj x).im = -x.im := rfl theorem norm_conj (x : gaussInt) : norm (conj x) = norm x := by simp [norm] instance : Div gaussInt := ⟨fun x y => ⟨Int.div' (x * conj y).re (norm y), Int.div' (x * conj y).im (norm y)⟩⟩ instance : Mod gaussInt := ⟨fun x y => x - y * (x / y)⟩ theorem div_def (x y : gaussInt) : x / y = ⟨Int.div' (x * conj y).re (norm y), Int.div' (x * conj y).im (norm y)⟩ := rfl theorem mod_def (x y : gaussInt) : x % y = x - y * (x / y) := rfl theorem norm_mod_lt (x : gaussInt) {y : gaussInt} (hy : y ≠ 0) : (x % y).norm < y.norm := by have norm_y_pos : 0 < norm y := by rwa [norm_pos] have : x % y * conj y = ⟨Int.mod' (x * conj y).re (norm y), Int.mod' (x * conj y).im (norm y)⟩ := by rw [mod_def, sub_mul, Int.mod'_eq, Int.mod'_eq, sub_eq_add_neg, div_def, norm] ext <;> simp <;> ring have : norm (x % y) * norm y ≤ norm y / 2 * norm y := by conv => lhs rw [← norm_conj y, ← norm_mul, this, norm] simp trans 2 * (y.norm / 2) ^ 2 · rw [two_mul] apply add_le_add <;> · rw [sq_le_sq] apply le_trans (Int.abs_mod'_le _ _ norm_y_pos) apply le_abs_self rw [pow_two, ← mul_assoc, mul_comm, mul_comm (2 : ℤ)] apply mul_le_mul_of_nonneg_left · apply Int.ediv_mul_le norm_num apply Int.ediv_nonneg (norm_nonneg y) norm_num have : norm (x % y) ≤ norm y / 2 := le_of_mul_le_mul_right this norm_y_pos apply lt_of_le_of_lt this apply Int.ediv_lt_of_lt_mul · norm_num linarith theorem coe_natAbs_norm (x : gaussInt) : (x.norm.natAbs : ℤ) = x.norm := Int.natAbs_of_nonneg (norm_nonneg _) theorem natAbs_norm_mod_lt (x y : gaussInt) (hy : y ≠ 0) : (x % y).norm.natAbs < y.norm.natAbs := by apply Int.ofNat_lt.1 simp only [Int.coe_natAbs, abs_of_nonneg, norm_nonneg] apply norm_mod_lt x hy theorem not_norm_mul_left_lt_norm (x : gaussInt) {y : gaussInt} (hy : y ≠ 0) : ¬(norm (x * y)).natAbs < (norm x).natAbs := by apply not_lt_of_ge rw [norm_mul, Int.natAbs_mul] apply le_mul_of_one_le_right (Nat.zero_le _) apply Int.ofNat_le.1 rw [coe_natAbs_norm] exact Int.add_one_le_of_lt ((norm_pos _).mpr hy) instance : EuclideanDomain gaussInt := { gaussInt.instCommRing with quotient := (· / ·) remainder := (· % ·) quotient_mul_add_remainder_eq := fun x y => by simp only; rw [mod_def, add_comm, sub_add_cancel] quotient_zero := fun x => by simp [div_def, norm, Int.div'] rfl r := Measure (Int.natAbs ∘ norm) r_wellFounded := (measure (Int.natAbs ∘ norm)).2 remainder_lt := natAbs_norm_mod_lt mul_left_not_lt := not_norm_mul_left_lt_norm } example (x : gaussInt) : Irreducible x ↔ Prime x := PrincipalIdealRing.irreducible_iff_prime end gaussInt
-
-
-
@@ -0,0 +1,224 @@import Mathlib.Algebra.BigOperators.Ring import Mathlib.Data.Real.Basic namespace C06S01 noncomputable section @[ext] structure Point where x : ℝ y : ℝ z : ℝ #check Point.ext example (a b : Point) (hx : a.x = b.x) (hy : a.y = b.y) (hz : a.z = b.z) : a = b := by ext repeat' assumption def myPoint1 : Point where x := 2 y := -1 z := 4 def myPoint2 : Point := ⟨2, -1, 4⟩ def myPoint3 := Point.mk 2 (-1) 4 structure Point' where build :: x : ℝ y : ℝ z : ℝ #check Point'.build 2 (-1) 4 namespace Point def add (a b : Point) : Point := ⟨a.x + b.x, a.y + b.y, a.z + b.z⟩ def add' (a b : Point) : Point where x := a.x + b.x y := a.y + b.y z := a.z + b.z #check add myPoint1 myPoint2 #check myPoint1.add myPoint2 end Point #check Point.add myPoint1 myPoint2 #check myPoint1.add myPoint2 namespace Point protected theorem add_comm (a b : Point) : add a b = add b a := by rw [add, add] ext <;> dsimp repeat' apply add_comm example (a b : Point) : add a b = add b a := by simp [add, add_comm] theorem add_x (a b : Point) : (a.add b).x = a.x + b.x := rfl def addAlt : Point → Point → Point | Point.mk x₁ y₁ z₁, Point.mk x₂ y₂ z₂ => ⟨x₁ + x₂, y₁ + y₂, z₁ + z₂⟩ def addAlt' : Point → Point → Point | ⟨x₁, y₁, z₁⟩, ⟨x₂, y₂, z₂⟩ => ⟨x₁ + x₂, y₁ + y₂, z₁ + z₂⟩ theorem addAlt_x (a b : Point) : (a.addAlt b).x = a.x + b.x := by cases a cases b rfl theorem addAlt_comm (a b : Point) : addAlt a b = addAlt b a := by rcases a with ⟨xa, ya, za⟩ rcases b with ⟨xb, yb, zb⟩ rw [addAlt, addAlt] ext <;> dsimp apply add_comm repeat' apply add_comm example (a b : Point) : addAlt a b = addAlt b a := by rcases a with ⟨xa, ya, za⟩ rcases b with ⟨xb, yb, zb⟩ simp [addAlt, add_comm] example : ∀ a b : Point, addAlt a b = addAlt b a := by rintro ⟨xa, ya, za⟩ ⟨xb, yb, zb⟩ simp [addAlt, add_comm] example : ∀ a b : Point, add a b = add b a := fun ⟨xa, ya, za⟩ ⟨xb, yb, zb⟩ => by simp [add, add_comm] protected theorem add_assoc (a b c : Point) : (a.add b).add c = a.add (b.add c) := by sorry def smul (r : ℝ) (a : Point) : Point := sorry theorem smul_distrib (r : ℝ) (a b : Point) : (smul r a).add (smul r b) = smul r (a.add b) := by sorry end Point structure StandardTwoSimplex where x : ℝ y : ℝ z : ℝ x_nonneg : 0 ≤ x y_nonneg : 0 ≤ y z_nonneg : 0 ≤ z sum_eq : x + y + z = 1 namespace StandardTwoSimplex def swapXy (a : StandardTwoSimplex) : StandardTwoSimplex where x := a.y y := a.x z := a.z x_nonneg := a.y_nonneg y_nonneg := a.x_nonneg z_nonneg := a.z_nonneg sum_eq := by rw [add_comm a.y a.x, a.sum_eq] noncomputable section def midpoint (a b : StandardTwoSimplex) : StandardTwoSimplex where x := (a.x + b.x) / 2 y := (a.y + b.y) / 2 z := (a.z + b.z) / 2 x_nonneg := div_nonneg (add_nonneg a.x_nonneg b.x_nonneg) (by norm_num) y_nonneg := div_nonneg (add_nonneg a.y_nonneg b.y_nonneg) (by norm_num) z_nonneg := div_nonneg (add_nonneg a.z_nonneg b.z_nonneg) (by norm_num) sum_eq := by field_simp; linarith [a.sum_eq, b.sum_eq] def weightedAverage (lambda : Real) (lambda_nonneg : 0 ≤ lambda) (lambda_le : lambda ≤ 1) (a b : StandardTwoSimplex) : StandardTwoSimplex := sorry end end StandardTwoSimplex open BigOperators structure StandardSimplex (n : ℕ) where V : Fin n → ℝ NonNeg : ∀ i : Fin n, 0 ≤ V i sum_eq_one : (∑ i, V i) = 1 namespace StandardSimplex def midpoint (n : ℕ) (a b : StandardSimplex n) : StandardSimplex n where V i := (a.V i + b.V i) / 2 NonNeg := by intro i apply div_nonneg · linarith [a.NonNeg i, b.NonNeg i] norm_num sum_eq_one := by simp [div_eq_mul_inv, ← Finset.sum_mul, Finset.sum_add_distrib, a.sum_eq_one, b.sum_eq_one] field_simp end StandardSimplex structure IsLinear (f : ℝ → ℝ) where is_additive : ∀ x y, f (x + y) = f x + f y preserves_mul : ∀ x c, f (c * x) = c * f x section variable (f : ℝ → ℝ) (linf : IsLinear f) #check linf.is_additive #check linf.preserves_mul end def Point'' := ℝ × ℝ × ℝ def IsLinear' (f : ℝ → ℝ) := (∀ x y, f (x + y) = f x + f y) ∧ ∀ x c, f (c * x) = c * f x def PReal := { y : ℝ // 0 < y } section variable (x : PReal) #check x.val #check x.property #check x.1 #check x.2 end def StandardTwoSimplex' := { p : ℝ × ℝ × ℝ // 0 ≤ p.1 ∧ 0 ≤ p.2.1 ∧ 0 ≤ p.2.2 ∧ p.1 + p.2.1 + p.2.2 = 1 } def StandardSimplex' (n : ℕ) := { v : Fin n → ℝ // (∀ i : Fin n, 0 ≤ v i) ∧ (∑ i, v i) = 1 } def StdSimplex := Σ n : ℕ, StandardSimplex n section variable (s : StdSimplex) #check s.fst #check s.snd #check s.1 #check s.2 end
-
-
-
@@ -0,0 +1,171 @@import Mathlib.Data.Real.Basic namespace C06S02 structure Group₁ (α : Type _) where mul : α → α → α one : α inv : α → α mul_assoc : ∀ x y z : α, mul (mul x y) z = mul x (mul y z) mul_one : ∀ x : α, mul x one = x one_mul : ∀ x : α, mul one x = x mul_left_inv : ∀ x : α, mul (inv x) x = one structure Group₁Cat where α : Type _ str : Group₁ α section variable (α β γ : Type _) variable (f : α ≃ β) (g : β ≃ γ) #check Equiv α β #check (f.toFun : α → β) #check (f.invFun : β → α) #check (f.right_inv : ∀ x : β, f (f.invFun x) = x) #check (f.left_inv : ∀ x : α, f.invFun (f x) = x) #check (Equiv.refl α : α ≃ α) #check (f.symm : β ≃ α) #check (f.trans g : α ≃ γ) example (x : α) : (f.trans g).toFun x = g.toFun (f.toFun x) := rfl example (x : α) : (f.trans g) x = g (f x) := rfl example : (f.trans g : α → γ) = g ∘ f := rfl end example (α : Type _) : Equiv.Perm α = (α ≃ α) := rfl def permGroup {α : Type _} : Group₁ (Equiv.Perm α) where mul f g := Equiv.trans g f one := Equiv.refl α inv := Equiv.symm mul_assoc f g h := (Equiv.trans_assoc _ _ _).symm one_mul := Equiv.trans_refl mul_one := Equiv.refl_trans mul_left_inv := Equiv.self_trans_symm structure AddGroup₁ (α : Type _) where (add : α → α → α) -- fill in the rest @[ext] structure Point where x : ℝ y : ℝ z : ℝ namespace Point def add (a b : Point) : Point := ⟨a.x + b.x, a.y + b.y, a.z + b.z⟩ def neg (a : Point) : Point := sorry def zero : Point := sorry def addGroupPoint : AddGroup₁ Point := sorry end Point section variable {α : Type _} (f g : Equiv.Perm α) (n : ℕ) #check f * g #check mul_assoc f g g⁻¹ -- group power, defined for any group #check g ^ n example : f * g * g⁻¹ = f := by rw [mul_assoc, mul_right_inv, mul_one] example : f * g * g⁻¹ = f := mul_inv_cancel_right f g example {α : Type _} (f g : Equiv.Perm α) : g.symm.trans (g.trans f) = f := mul_inv_cancel_right f g end class Group₂ (α : Type _) where mul : α → α → α one : α inv : α → α mul_assoc : ∀ x y z : α, mul (mul x y) z = mul x (mul y z) mul_one : ∀ x : α, mul x one = x one_mul : ∀ x : α, mul one x = x mul_left_inv : ∀ x : α, mul (inv x) x = one instance {α : Type _} : Group₂ (Equiv.Perm α) where mul f g := Equiv.trans g f one := Equiv.refl α inv := Equiv.symm mul_assoc f g h := (Equiv.trans_assoc _ _ _).symm one_mul := Equiv.trans_refl mul_one := Equiv.refl_trans mul_left_inv := Equiv.self_trans_symm #check @Group₂.mul def mySquare {α : Type _} [Group₂ α] (x : α) := Group₂.mul x x #check @mySquare section variable {β : Type _} (f g : Equiv.Perm β) example : Group₂.mul f g = g.trans f := rfl example : mySquare f = f.trans f := rfl end instance : Inhabited Point where default := ⟨0, 0, 0⟩ #check (default : Point) example : ([] : List Point).headI = default := rfl instance : Add Point where add := Point.add section variable (x y : Point) #check x + y example : x + y = Point.add x y := rfl end instance hasMulGroup₂ {α : Type _} [Group₂ α] : Mul α := ⟨Group₂.mul⟩ instance hasOneGroup₂ {α : Type _} [Group₂ α] : One α := ⟨Group₂.one⟩ instance hasInvGroup₂ {α : Type _} [Group₂ α] : Inv α := ⟨Group₂.inv⟩ section variable {α : Type _} (f g : Equiv.Perm α) #check f * 1 * g⁻¹ def foo : f * 1 * g⁻¹ = g.symm.trans ((Equiv.refl α).trans f) := rfl end class AddGroup₂ (α : Type _) where add : α → α → α -- fill in the rest
-
-
-
@@ -0,0 +1,273 @@import Mathlib.Data.Int.Basic import Mathlib.Algebra.EuclideanDomain.Basic import Mathlib.RingTheory.PrincipalIdealDomain import Mathlib.Tactic @[ext] structure gaussInt where re : ℤ im : ℤ namespace gaussInt instance : Zero gaussInt := ⟨⟨0, 0⟩⟩ instance : One gaussInt := ⟨⟨1, 0⟩⟩ instance : Add gaussInt := ⟨fun x y => ⟨x.re + y.re, x.im + y.im⟩⟩ instance : Neg gaussInt := ⟨fun x => ⟨-x.re, -x.im⟩⟩ instance : Mul gaussInt := ⟨fun x y => ⟨x.re * y.re - x.im * y.im, x.re * y.im + x.im * y.re⟩⟩ theorem zero_def : (0 : gaussInt) = ⟨0, 0⟩ := rfl theorem one_def : (1 : gaussInt) = ⟨1, 0⟩ := rfl theorem add_def (x y : gaussInt) : x + y = ⟨x.re + y.re, x.im + y.im⟩ := rfl theorem neg_def (x : gaussInt) : -x = ⟨-x.re, -x.im⟩ := rfl theorem mul_def (x y : gaussInt) : x * y = ⟨x.re * y.re - x.im * y.im, x.re * y.im + x.im * y.re⟩ := rfl @[simp] theorem zero_re : (0 : gaussInt).re = 0 := rfl @[simp] theorem zero_im : (0 : gaussInt).im = 0 := rfl @[simp] theorem one_re : (1 : gaussInt).re = 1 := rfl @[simp] theorem one_im : (1 : gaussInt).im = 0 := rfl @[simp] theorem add_re (x y : gaussInt) : (x + y).re = x.re + y.re := rfl @[simp] theorem add_im (x y : gaussInt) : (x + y).im = x.im + y.im := rfl @[simp] theorem neg_re (x : gaussInt) : (-x).re = -x.re := rfl @[simp] theorem neg_im (x : gaussInt) : (-x).im = -x.im := rfl @[simp] theorem mul_re (x y : gaussInt) : (x * y).re = x.re * y.re - x.im * y.im := rfl @[simp] theorem mul_im (x y : gaussInt) : (x * y).im = x.re * y.im + x.im * y.re := rfl instance instCommRing : CommRing gaussInt where zero := 0 one := 1 add := (· + ·) neg x := -x mul := (· * ·) add_assoc := by intros ext <;> simp <;> ring zero_add := by intro ext <;> simp add_zero := by intro ext <;> simp add_left_neg := by intro ext <;> simp add_comm := by intros ext <;> simp <;> ring mul_assoc := by intros ext <;> simp <;> ring one_mul := by intro ext <;> simp mul_one := by intro ext <;> simp left_distrib := by intros ext <;> simp <;> ring right_distrib := by intros ext <;> simp <;> ring mul_comm := by intros ext <;> simp <;> ring zero_mul := sorry mul_zero := sorry @[simp] theorem sub_re (x y : gaussInt) : (x - y).re = x.re - y.re := rfl @[simp] theorem sub_im (x y : gaussInt) : (x - y).im = x.im - y.im := rfl instance : Nontrivial gaussInt := by use 0, 1 rw [Ne, gaussInt.ext_iff] simp end gaussInt example (a b : ℤ) : a = b * (a / b) + a % b := Eq.symm <| Int.ediv_add_emod a b example (a b : ℤ) : b ≠ 0 → 0 ≤ a % b := Int.emod_nonneg a example (a b : ℤ) : b ≠ 0 → a % b < abs b := Int.emod_lt a namespace Int def div' (a b : ℤ) := (a + b / 2) / b def mod' (a b : ℤ) := (a + b / 2) % b - b / 2 theorem div'_add_mod' (a b : ℤ) : b * div' a b + mod' a b = a := by rw [div', mod'] linarith [Int.ediv_add_emod (a + b / 2) b] theorem abs_mod'_le (a b : ℤ) (h : 0 < b) : abs (mod' a b) ≤ b / 2 := by rw [mod', abs_le] constructor · linarith [Int.emod_nonneg (a + b / 2) h.ne'] have := Int.emod_lt_of_pos (a + b / 2) h have := Int.ediv_add_emod b 2 have := Int.emod_lt_of_pos b zero_lt_two revert this; intro this -- FIXME, this should not be needed linarith theorem mod'_eq (a b : ℤ) : mod' a b = a - b * div' a b := by linarith [div'_add_mod' a b] end Int theorem sq_add_sq_eq_zero {α : Type _} [LinearOrderedRing α] (x y : α) : x ^ 2 + y ^ 2 = 0 ↔ x = 0 ∧ y = 0 := by sorry namespace gaussInt def norm (x : gaussInt) := x.re ^ 2 + x.im ^ 2 @[simp] theorem norm_nonneg (x : gaussInt) : 0 ≤ norm x := by sorry theorem norm_eq_zero (x : gaussInt) : norm x = 0 ↔ x = 0 := by sorry theorem norm_pos (x : gaussInt) : 0 < norm x ↔ x ≠ 0 := by sorry theorem norm_mul (x y : gaussInt) : norm (x * y) = norm x * norm y := by sorry def conj (x : gaussInt) : gaussInt := ⟨x.re, -x.im⟩ @[simp] theorem conj_re (x : gaussInt) : (conj x).re = x.re := rfl @[simp] theorem conj_im (x : gaussInt) : (conj x).im = -x.im := rfl theorem norm_conj (x : gaussInt) : norm (conj x) = norm x := by simp [norm] instance : Div gaussInt := ⟨fun x y => ⟨Int.div' (x * conj y).re (norm y), Int.div' (x * conj y).im (norm y)⟩⟩ instance : Mod gaussInt := ⟨fun x y => x - y * (x / y)⟩ theorem div_def (x y : gaussInt) : x / y = ⟨Int.div' (x * conj y).re (norm y), Int.div' (x * conj y).im (norm y)⟩ := rfl theorem mod_def (x y : gaussInt) : x % y = x - y * (x / y) := rfl theorem norm_mod_lt (x : gaussInt) {y : gaussInt} (hy : y ≠ 0) : (x % y).norm < y.norm := by have norm_y_pos : 0 < norm y := by rwa [norm_pos] have H1 : x % y * conj y = ⟨Int.mod' (x * conj y).re (norm y), Int.mod' (x * conj y).im (norm y)⟩ · ext <;> simp [Int.mod'_eq, mod_def, div_def, norm] <;> ring have H2 : norm (x % y) * norm y ≤ norm y / 2 * norm y · calc norm (x % y) * norm y = norm (x % y * conj y) := by simp only [norm_mul, norm_conj] _ = abs (Int.mod' (x.re * y.re + x.im * y.im) (norm y)) ^ 2 + abs (Int.mod' (-(x.re * y.im) + x.im * y.re) (norm y)) ^ 2 := by simp [H1, norm, sq_abs] _ ≤ (y.norm / 2) ^ 2 + (y.norm / 2) ^ 2 := by gcongr <;> apply Int.abs_mod'_le _ _ norm_y_pos _ = norm y / 2 * (norm y / 2 * 2) := by ring _ ≤ norm y / 2 * norm y := by gcongr; apply Int.ediv_mul_le; norm_num calc norm (x % y) ≤ norm y / 2 := le_of_mul_le_mul_right H2 norm_y_pos _ < norm y := by apply Int.ediv_lt_of_lt_mul · norm_num · linarith theorem coe_natAbs_norm (x : gaussInt) : (x.norm.natAbs : ℤ) = x.norm := Int.natAbs_of_nonneg (norm_nonneg _) theorem natAbs_norm_mod_lt (x y : gaussInt) (hy : y ≠ 0) : (x % y).norm.natAbs < y.norm.natAbs := by apply Int.ofNat_lt.1 simp only [Int.coe_natAbs, abs_of_nonneg, norm_nonneg] apply norm_mod_lt x hy theorem not_norm_mul_left_lt_norm (x : gaussInt) {y : gaussInt} (hy : y ≠ 0) : ¬(norm (x * y)).natAbs < (norm x).natAbs := by apply not_lt_of_ge rw [norm_mul, Int.natAbs_mul] apply le_mul_of_one_le_right (Nat.zero_le _) apply Int.ofNat_le.1 rw [coe_natAbs_norm] exact Int.add_one_le_of_lt ((norm_pos _).mpr hy) instance : EuclideanDomain gaussInt := { gaussInt.instCommRing with quotient := (· / ·) remainder := (· % ·) quotient_mul_add_remainder_eq := fun x y => by simp only; rw [mod_def, add_comm, sub_add_cancel] quotient_zero := fun x => by simp [div_def, norm, Int.div'] rfl r := Measure (Int.natAbs ∘ norm) r_wellFounded := (measure (Int.natAbs ∘ norm)).2 remainder_lt := natAbs_norm_mod_lt mul_left_not_lt := not_norm_mul_left_lt_norm } example (x : gaussInt) : Irreducible x ↔ Prime x := PrincipalIdealRing.irreducible_iff_prime end gaussInt
-
-
-
@@ -0,0 +1,99 @@import Mathlib.Algebra.BigOperators.Ring import Mathlib.Data.Real.Basic namespace C06S01 noncomputable section @[ext] structure Point where x : ℝ y : ℝ z : ℝ namespace Point def add (a b : Point) : Point := ⟨a.x + b.x, a.y + b.y, a.z + b.z⟩ protected theorem add_assoc (a b c : Point) : (a.add b).add c = a.add (b.add c) := by simp [add, add_assoc] def smul (r : ℝ) (a : Point) : Point := ⟨r * a.x, r * a.y, r * a.z⟩ theorem smul_distrib (r : ℝ) (a b : Point) : (smul r a).add (smul r b) = smul r (a.add b) := by simp [add, smul, mul_add] end Point structure StandardTwoSimplex where x : ℝ y : ℝ z : ℝ x_nonneg : 0 ≤ x y_nonneg : 0 ≤ y z_nonneg : 0 ≤ z sum_eq : x + y + z = 1 namespace StandardTwoSimplex noncomputable section def weightedAverage (lambda : Real) (lambda_nonneg : 0 ≤ lambda) (lambda_le : lambda ≤ 1) (a b : StandardTwoSimplex) : StandardTwoSimplex where x := lambda * a.x + (1 - lambda) * b.x y := lambda * a.y + (1 - lambda) * b.y z := lambda * a.z + (1 - lambda) * b.z x_nonneg := add_nonneg (mul_nonneg lambda_nonneg a.x_nonneg) (mul_nonneg (by linarith) b.x_nonneg) y_nonneg := add_nonneg (mul_nonneg lambda_nonneg a.y_nonneg) (mul_nonneg (by linarith) b.y_nonneg) z_nonneg := add_nonneg (mul_nonneg lambda_nonneg a.z_nonneg) (mul_nonneg (by linarith) b.z_nonneg) sum_eq := by trans (a.x + a.y + a.z) * lambda + (b.x + b.y + b.z) * (1 - lambda) · ring simp [a.sum_eq, b.sum_eq] end end StandardTwoSimplex open BigOperators structure StandardSimplex (n : ℕ) where V : Fin n → ℝ NonNeg : ∀ i : Fin n, 0 ≤ V i sum_eq_one : (∑ i, V i) = 1 namespace StandardSimplex def midpoint (n : ℕ) (a b : StandardSimplex n) : StandardSimplex n where V i := (a.V i + b.V i) / 2 NonNeg := by intro i apply div_nonneg · linarith [a.NonNeg i, b.NonNeg i] norm_num sum_eq_one := by simp [div_eq_mul_inv, ← Finset.sum_mul, Finset.sum_add_distrib, a.sum_eq_one, b.sum_eq_one] field_simp end StandardSimplex namespace StandardSimplex def weightedAverage {n : ℕ} (lambda : Real) (lambda_nonneg : 0 ≤ lambda) (lambda_le : lambda ≤ 1) (a b : StandardSimplex n) : StandardSimplex n where V i := lambda * a.V i + (1 - lambda) * b.V i NonNeg i := add_nonneg (mul_nonneg lambda_nonneg (a.NonNeg i)) (mul_nonneg (by linarith) (b.NonNeg i)) sum_eq_one := by trans (lambda * ∑ i, a.V i) + (1 - lambda) * ∑ i, b.V i · rw [Finset.sum_add_distrib, Finset.mul_sum, Finset.mul_sum] simp [a.sum_eq_one, b.sum_eq_one] end StandardSimplex
-
-
-
@@ -0,0 +1,74 @@import Mathlib.Data.Real.Basic namespace C06S02 structure AddGroup₁ (α : Type _) where add : α → α → α zero : α neg : α → α add_assoc : ∀ x y z : α, add (add x y) z = add x (add y z) add_zero : ∀ x : α, add x zero = x zero_add : ∀ x : α, add x zero = x add_left_neg : ∀ x : α, add (neg x) x = zero @[ext] structure Point where x : ℝ y : ℝ z : ℝ namespace Point def add (a b : Point) : Point := ⟨a.x + b.x, a.y + b.y, a.z + b.z⟩ def neg (a : Point) : Point := ⟨-a.x, -a.y, -a.z⟩ def zero : Point := ⟨0, 0, 0⟩ def addGroupPoint : AddGroup₁ Point where add := Point.add zero := Point.zero neg := Point.neg add_assoc := by simp [Point.add, add_assoc] add_zero := by simp [Point.add, Point.zero] zero_add := by simp [Point.add, Point.zero] add_left_neg := by simp [Point.add, Point.neg, Point.zero] end Point class AddGroup₂ (α : Type _) where add : α → α → α zero : α neg : α → α add_assoc : ∀ x y z : α, add (add x y) z = add x (add y z) add_zero : ∀ x : α, add x zero = x zero_add : ∀ x : α, add x zero = x add_left_neg : ∀ x : α, add (neg x) x = zero instance hasAddAddGroup₂ {α : Type _} [AddGroup₂ α] : Add α := ⟨AddGroup₂.add⟩ instance hasZeroAddGroup₂ {α : Type _} [AddGroup₂ α] : Zero α := ⟨AddGroup₂.zero⟩ instance hasNegAddGroup₂ {α : Type _} [AddGroup₂ α] : Neg α := ⟨AddGroup₂.neg⟩ instance : AddGroup₂ Point where add := Point.add zero := Point.zero neg := Point.neg add_assoc := by simp [Point.add, add_assoc] add_zero := by simp [Point.add, Point.zero] zero_add := by simp [Point.add, Point.zero] add_left_neg := by simp [Point.add, Point.neg, Point.zero] section variable (x y : Point) #check x + -y + 0 end
-
-
-
@@ -0,0 +1,287 @@import Mathlib.Data.Int.Basic import Mathlib.Algebra.EuclideanDomain.Basic import Mathlib.RingTheory.PrincipalIdealDomain import Mathlib.Tactic @[ext] structure gaussInt where re : ℤ im : ℤ namespace gaussInt instance : Zero gaussInt := ⟨⟨0, 0⟩⟩ instance : One gaussInt := ⟨⟨1, 0⟩⟩ instance : Add gaussInt := ⟨fun x y => ⟨x.re + y.re, x.im + y.im⟩⟩ instance : Neg gaussInt := ⟨fun x => ⟨-x.re, -x.im⟩⟩ instance : Mul gaussInt := ⟨fun x y => ⟨x.re * y.re - x.im * y.im, x.re * y.im + x.im * y.re⟩⟩ theorem zero_def : (0 : gaussInt) = ⟨0, 0⟩ := rfl theorem one_def : (1 : gaussInt) = ⟨1, 0⟩ := rfl theorem add_def (x y : gaussInt) : x + y = ⟨x.re + y.re, x.im + y.im⟩ := rfl theorem neg_def (x : gaussInt) : -x = ⟨-x.re, -x.im⟩ := rfl theorem mul_def (x y : gaussInt) : x * y = ⟨x.re * y.re - x.im * y.im, x.re * y.im + x.im * y.re⟩ := rfl @[simp] theorem zero_re : (0 : gaussInt).re = 0 := rfl @[simp] theorem zero_im : (0 : gaussInt).im = 0 := rfl @[simp] theorem one_re : (1 : gaussInt).re = 1 := rfl @[simp] theorem one_im : (1 : gaussInt).im = 0 := rfl @[simp] theorem add_re (x y : gaussInt) : (x + y).re = x.re + y.re := rfl @[simp] theorem add_im (x y : gaussInt) : (x + y).im = x.im + y.im := rfl @[simp] theorem neg_re (x : gaussInt) : (-x).re = -x.re := rfl @[simp] theorem neg_im (x : gaussInt) : (-x).im = -x.im := rfl @[simp] theorem mul_re (x y : gaussInt) : (x * y).re = x.re * y.re - x.im * y.im := rfl @[simp] theorem mul_im (x y : gaussInt) : (x * y).im = x.re * y.im + x.im * y.re := rfl instance instCommRing : CommRing gaussInt where zero := 0 one := 1 add := (· + ·) neg x := -x mul := (· * ·) add_assoc := by intros ext <;> simp <;> ring zero_add := by intro ext <;> simp add_zero := by intro ext <;> simp add_left_neg := by intro ext <;> simp add_comm := by intros ext <;> simp <;> ring mul_assoc := by intros ext <;> simp <;> ring one_mul := by intro ext <;> simp mul_one := by intro ext <;> simp left_distrib := by intros ext <;> simp <;> ring right_distrib := by intros ext <;> simp <;> ring mul_comm := by intros ext <;> simp <;> ring zero_mul := sorry mul_zero := sorry @[simp] theorem sub_re (x y : gaussInt) : (x - y).re = x.re - y.re := rfl @[simp] theorem sub_im (x y : gaussInt) : (x - y).im = x.im - y.im := rfl instance : Nontrivial gaussInt := by use 0, 1 rw [Ne, gaussInt.ext_iff] simp end gaussInt namespace Int def div' (a b : ℤ) := (a + b / 2) / b def mod' (a b : ℤ) := (a + b / 2) % b - b / 2 theorem div'_add_mod' (a b : ℤ) : b * div' a b + mod' a b = a := by rw [div', mod'] linarith [Int.ediv_add_emod (a + b / 2) b] theorem abs_mod'_le (a b : ℤ) (h : 0 < b) : abs (mod' a b) ≤ b / 2 := by rw [mod', abs_le] constructor · linarith [Int.emod_nonneg (a + b / 2) h.ne'] have := Int.emod_lt_of_pos (a + b / 2) h have := Int.ediv_add_emod b 2 have := Int.emod_lt_of_pos b zero_lt_two revert this; intro this -- FIXME, this should not be needed linarith theorem mod'_eq (a b : ℤ) : mod' a b = a - b * div' a b := by linarith [div'_add_mod' a b] end Int private theorem aux {α : Type _} [LinearOrderedRing α] {x y : α} (h : x ^ 2 + y ^ 2 = 0) : x = 0 := haveI h' : x ^ 2 = 0 := by apply le_antisymm _ (sq_nonneg x) rw [← h] apply le_add_of_nonneg_right (sq_nonneg y) pow_eq_zero h' theorem sq_add_sq_eq_zero {α : Type _} [LinearOrderedRing α] (x y : α) : x ^ 2 + y ^ 2 = 0 ↔ x = 0 ∧ y = 0 := by constructor · intro h constructor · exact aux h rw [add_comm] at h exact aux h rintro ⟨rfl, rfl⟩ norm_num namespace gaussInt def norm (x : gaussInt) := x.re ^ 2 + x.im ^ 2 @[simp] theorem norm_nonneg (x : gaussInt) : 0 ≤ norm x := by apply add_nonneg <;> apply sq_nonneg theorem norm_eq_zero (x : gaussInt) : norm x = 0 ↔ x = 0 := by rw [norm, sq_add_sq_eq_zero, gaussInt.ext_iff] rfl theorem norm_pos (x : gaussInt) : 0 < norm x ↔ x ≠ 0 := by rw [lt_iff_le_and_ne, ne_comm, Ne, norm_eq_zero] simp [norm_nonneg] theorem norm_mul (x y : gaussInt) : norm (x * y) = norm x * norm y := by simp [norm] ring def conj (x : gaussInt) : gaussInt := ⟨x.re, -x.im⟩ @[simp] theorem conj_re (x : gaussInt) : (conj x).re = x.re := rfl @[simp] theorem conj_im (x : gaussInt) : (conj x).im = -x.im := rfl theorem norm_conj (x : gaussInt) : norm (conj x) = norm x := by simp [norm] instance : Div gaussInt := ⟨fun x y => ⟨Int.div' (x * conj y).re (norm y), Int.div' (x * conj y).im (norm y)⟩⟩ instance : Mod gaussInt := ⟨fun x y => x - y * (x / y)⟩ theorem div_def (x y : gaussInt) : x / y = ⟨Int.div' (x * conj y).re (norm y), Int.div' (x * conj y).im (norm y)⟩ := rfl theorem mod_def (x y : gaussInt) : x % y = x - y * (x / y) := rfl theorem norm_mod_lt (x : gaussInt) {y : gaussInt} (hy : y ≠ 0) : (x % y).norm < y.norm := by have norm_y_pos : 0 < norm y := by rwa [norm_pos] have H1 : x % y * conj y = ⟨Int.mod' (x * conj y).re (norm y), Int.mod' (x * conj y).im (norm y)⟩ · ext <;> simp [Int.mod'_eq, mod_def, div_def, norm] <;> ring have H2 : norm (x % y) * norm y ≤ norm y / 2 * norm y · calc norm (x % y) * norm y = norm (x % y * conj y) := by simp only [norm_mul, norm_conj] _ = abs (Int.mod' (x.re * y.re + x.im * y.im) (norm y)) ^ 2 + abs (Int.mod' (-(x.re * y.im) + x.im * y.re) (norm y)) ^ 2 := by simp [H1, norm, sq_abs] _ ≤ (y.norm / 2) ^ 2 + (y.norm / 2) ^ 2 := by gcongr <;> apply Int.abs_mod'_le _ _ norm_y_pos _ = norm y / 2 * (norm y / 2 * 2) := by ring _ ≤ norm y / 2 * norm y := by gcongr; apply Int.ediv_mul_le; norm_num calc norm (x % y) ≤ norm y / 2 := le_of_mul_le_mul_right H2 norm_y_pos _ < norm y := by apply Int.ediv_lt_of_lt_mul · norm_num · linarith theorem coe_natAbs_norm (x : gaussInt) : (x.norm.natAbs : ℤ) = x.norm := Int.natAbs_of_nonneg (norm_nonneg _) theorem natAbs_norm_mod_lt (x y : gaussInt) (hy : y ≠ 0) : (x % y).norm.natAbs < y.norm.natAbs := by apply Int.ofNat_lt.1 simp only [Int.coe_natAbs, abs_of_nonneg, norm_nonneg] apply norm_mod_lt x hy theorem not_norm_mul_left_lt_norm (x : gaussInt) {y : gaussInt} (hy : y ≠ 0) : ¬(norm (x * y)).natAbs < (norm x).natAbs := by apply not_lt_of_ge rw [norm_mul, Int.natAbs_mul] apply le_mul_of_one_le_right (Nat.zero_le _) apply Int.ofNat_le.1 rw [coe_natAbs_norm] exact Int.add_one_le_of_lt ((norm_pos _).mpr hy) instance : EuclideanDomain gaussInt := { gaussInt.instCommRing with quotient := (· / ·) remainder := (· % ·) quotient_mul_add_remainder_eq := fun x y => by simp only; rw [mod_def, add_comm, sub_add_cancel] quotient_zero := fun x => by simp [div_def, norm, Int.div'] rfl r := Measure (Int.natAbs ∘ norm) r_wellFounded := (measure (Int.natAbs ∘ norm)).2 remainder_lt := natAbs_norm_mod_lt mul_left_not_lt := not_norm_mul_left_lt_norm } example (x : gaussInt) : Irreducible x ↔ Prime x := PrincipalIdealRing.irreducible_iff_prime end gaussInt
-
-
-
@@ -0,0 +1,308 @@import Mathlib.Algebra.BigOperators.Ring import Mathlib.Data.Real.Basic class One₁ (α : Type) where /-- The element one -/ one : α #check One₁.one -- One₁.one {α : Type} [self : One₁ α] : α @[class] structure One₂ (α : Type) where /-- The element one -/ one : α #check One₂.one example (α : Type) [One₁ α] : α := One₁.one example (α : Type) [One₁ α] := (One₁.one : α) @[inherit_doc] notation "𝟙" => One₁.one example {α : Type} [One₁ α] : α := 𝟙 example {α : Type} [One₁ α] : (𝟙 : α) = 𝟙 := rfl class Dia₁ (α : Type) where dia : α → α → α infixl:70 " ⋄ " => Dia₁.dia class Semigroup₁ (α : Type) where toDia₁ : Dia₁ α /-- Diamond is associative -/ dia_assoc : ∀ a b c : α, a ⋄ b ⋄ c = a ⋄ (b ⋄ c) attribute [instance] Semigroup₁.toDia₁ example {α : Type} [Semigroup₁ α] (a b : α) : α := a ⋄ b class Semigroup₂ (α : Type) extends Dia₁ α where /-- Diamond is associative -/ dia_assoc : ∀ a b c : α, a ⋄ b ⋄ c = a ⋄ (b ⋄ c) example {α : Type} [Semigroup₂ α] (a b : α) : α := a ⋄ b class DiaOneClass₁ (α : Type) extends One₁ α, Dia₁ α where /-- One is a left neutral element for diamond. -/ one_dia : ∀ a : α, 𝟙 ⋄ a = a /-- One is a right neutral element for diamond -/ dia_one : ∀ a : α, a ⋄ 𝟙 = a set_option trace.Meta.synthInstance true in example {α : Type} [DiaOneClass₁ α] (a b : α) : Prop := a ⋄ b = 𝟙 class Monoid₁ (α : Type) extends Semigroup₁ α, DiaOneClass₁ α class Monoid₂ (α : Type) where toSemigroup₁ : Semigroup₁ α toDiaOneClass₁ : DiaOneClass₁ α example {α : Type} [Monoid₁ α] : (Monoid₁.toSemigroup₁.toDia₁.dia : α → α → α) = Monoid₁.toDiaOneClass₁.toDia₁.dia := rfl /- Monoid₂.mk {α : Type} (toSemigroup₁ : Semigroup₁ α) (toDiaOneClass₁ : DiaOneClass₁ α) : Monoid₂ α -/ #check Monoid₂.mk /- Monoid₁.mk {α : Type} [toSemigroup₁ : Semigroup₁ α] [toOne₁ : One₁ α] (one_dia : ∀ (a : α), 𝟙 ⋄ a = a) (dia_one : ∀ (a : α), a ⋄ 𝟙 = a) : Monoid₁ α -/ #check Monoid₁.mk #check Monoid₁.toSemigroup₁ #check Monoid₁.toDiaOneClass₁ class Inv₁ (α : Type) where /-- The inversion function -/ inv : α → α @[inherit_doc] postfix:max "⁻¹" => Inv₁.inv class Group₁ (G : Type) extends Monoid₁ G, Inv G where inv_dia : ∀ a : G, a⁻¹ ⋄ a = 𝟙 lemma left_inv_eq_right_inv₁ {M : Type} [Monoid₁ M] {a b c : M} (hba : b ⋄ a = 𝟙) (hac : a ⋄ c = 𝟙) : b = c := by rw [← DiaOneClass₁.one_dia c, ← hba, Semigroup₁.dia_assoc, hac, DiaOneClass₁.dia_one b] export DiaOneClass₁ (one_dia dia_one) export Semigroup₁ (dia_assoc) export Group₁ (inv_dia) example {M : Type} [Monoid₁ M] {a b c : M} (hba : b ⋄ a = 𝟙) (hac : a ⋄ c = 𝟙) : b = c := by rw [← one_dia c, ← hba, dia_assoc, hac, dia_one b] lemma inv_eq_of_dia [Group₁ G] {a b : G} (h : a ⋄ b = 𝟙) : a⁻¹ = b := sorry lemma dia_inv [Group₁ G] (a : G) : a ⋄ a⁻¹ = 𝟙 := sorry class AddSemigroup₃ (α : Type) extends Add α where /-- Multiplication is associative -/ add_assoc₃ : ∀ a b c : α, a + b + c = a + (b + c) @[to_additive AddSemigroup₃] class Semigroup₃ (α : Type) extends Mul α where /-- Multiplication is associative -/ mul_assoc₃ : ∀ a b c : α, a * b * c = a * (b * c) class AddMonoid₃ (α : Type) extends AddSemigroup₃ α, AddZeroClass α @[to_additive AddMonoid₃] class Monoid₃ (α : Type) extends Semigroup₃ α, MulOneClass α attribute [to_additive existing] Monoid₃.toMulOneClass export Semigroup₃ (mul_assoc₃) export AddSemigroup₃ (add_assoc₃) whatsnew in @[to_additive] lemma left_inv_eq_right_inv' {M : Type} [Monoid₃ M] {a b c : M} (hba : b * a = 1) (hac : a * c = 1) : b = c := by rw [← one_mul c, ← hba, mul_assoc₃, hac, mul_one b] #check left_neg_eq_right_neg' class AddCommSemigroup₃ (α : Type) extends AddSemigroup₃ α where add_comm : ∀ a b : α, a + b = b + a @[to_additive AddCommSemigroup₃] class CommSemigroup₃ (α : Type) extends Semigroup₃ α where mul_comm : ∀ a b : α, a * b = b * a class AddCommMonoid₃ (α : Type) extends AddMonoid₃ α, AddCommSemigroup₃ α @[to_additive AddCommMonoid₃] class CommMonoid₃ (α : Type) extends Monoid₃ α, CommSemigroup₃ α class AddGroup₃ (G : Type) extends AddMonoid₃ G, Neg G where neg_add : ∀ a : G, -a + a = 0 @[to_additive AddGroup₃] class Group₃ (G : Type) extends Monoid₃ G, Inv G where inv_mul : ∀ a : G, a⁻¹ * a = 1 attribute [simp] Group₃.inv_mul AddGroup₃.neg_add @[to_additive] lemma inv_eq_of_mul [Group₃ G] {a b : G} (h : a * b = 1) : a⁻¹ = b := sorry @[to_additive (attr := simp)] lemma Group₃.mul_inv {G : Type} [Group₃ G] {a : G} : a * a⁻¹ = 1 := by sorry @[to_additive] lemma mul_left_cancel₃ {G : Type} [Group₃ G] {a b c : G} (h : a * b = a * c) : b = c := by sorry @[to_additive] lemma mul_right_cancel₃ {G : Type} [Group₃ G] {a b c : G} (h : b*a = c*a) : b = c := by sorry class AddCommGroup₃ (G : Type) extends AddGroup₃ G, AddCommMonoid₃ G @[to_additive AddCommGroup₃] class CommGroup₃ (G : Type) extends Group₃ G, CommMonoid₃ G class Ring₃ (R : Type) extends AddGroup₃ R, Monoid₃ R, MulZeroClass R where /-- Multiplication is left distributive over addition -/ left_distrib : ∀ a b c : R, a * (b + c) = a * b + a * c /-- Multiplication is right distributive over addition -/ right_distrib : ∀ a b c : R, (a + b) * c = a * c + b * c instance {R : Type} [Ring₃ R] : AddCommGroup₃ R := { Ring₃.toAddGroup₃ with add_comm := by sorry } instance : Ring₃ ℤ where add := (· + ·) add_assoc₃ := add_assoc zero := 0 zero_add := by simp add_zero := by simp neg := (- ·) neg_add := by simp mul := (· * ·) mul_assoc₃ := mul_assoc one := 1 one_mul := by simp mul_one := by simp zero_mul := by simp mul_zero := by simp left_distrib := Int.mul_add right_distrib := Int.add_mul class LE₁ (α : Type) where /-- The Less-or-Equal relation. -/ le : α → α → Prop @[inherit_doc] infix:50 " ≤₁ " => LE₁.le class Preorder₁ (α : Type) class PartialOrder₁ (α : Type) class OrderedCommMonoid₁ (α : Type) instance : OrderedCommMonoid₁ ℕ where class SMul₃ (α : Type) (β : Type) where /-- Scalar multiplication -/ smul : α → β → β infixr:73 " • " => SMul₃.smul class Module₁ (R : Type) [Ring₃ R] (M : Type) [AddCommGroup₃ M] extends SMul₃ R M where zero_smul : ∀ m : M, (0 : R) • m = 0 one_smul : ∀ m : M, (1 : R) • m = m mul_smul : ∀ (a b : R) (m : M), (a * b) • m = a • b • m add_smul : ∀ (a b : R) (m : M), (a + b) • m = a • m + b • m smul_add : ∀ (a : R) (m n : M), a • (m + n) = a • m + a • n instance selfModule (R : Type) [Ring₃ R] : Module₁ R R where smul := fun r s ↦ r*s zero_smul := zero_mul one_smul := one_mul mul_smul := mul_assoc₃ add_smul := Ring₃.right_distrib smul_add := Ring₃.left_distrib def nsmul₁ [Zero M] [Add M] : ℕ → M → M | 0, _ => 0 | n + 1, a => a + nsmul₁ n a def zsmul₁ {M : Type _} [Zero M] [Add M] [Neg M] : ℤ → M → M | Int.ofNat n, a => nsmul₁ n a | Int.negSucc n, a => -nsmul₁ n.succ a instance abGrpModule (A : Type) [AddCommGroup₃ A] : Module₁ ℤ A where smul := zsmul₁ zero_smul := sorry one_smul := sorry mul_smul := sorry add_smul := sorry smul_add := sorry #synth Module₁ ℤ ℤ -- abGrpModule ℤ class AddMonoid₄ (M : Type) extends AddSemigroup₃ M, AddZeroClass M where /-- Multiplication by a natural number. -/ nsmul : ℕ → M → M := nsmul₁ /-- Multiplication by `(0 : ℕ)` gives `0`. -/ nsmul_zero : ∀ x, nsmul 0 x = 0 := by intros; rfl /-- Multiplication by `(n + 1 : ℕ)` behaves as expected. -/ nsmul_succ : ∀ (n : ℕ) (x), nsmul (n + 1) x = x + nsmul n x := by intros; rfl instance mySMul {M : Type} [AddMonoid₄ M] : SMul ℕ M := ⟨AddMonoid₄.nsmul⟩ instance (M N : Type) [AddMonoid₄ M] [AddMonoid₄ N] : AddMonoid₄ (M × N) where add := fun p q ↦ (p.1 + q.1, p.2 + q.2) add_assoc₃ := fun a b c ↦ by ext <;> apply add_assoc₃ zero := (0, 0) zero_add := fun a ↦ by ext <;> apply zero_add add_zero := fun a ↦ by ext <;> apply add_zero instance : AddMonoid₄ ℤ where add := (· + ·) add_assoc₃ := Int.add_assoc zero := 0 zero_add := Int.zero_add add_zero := Int.add_zero nsmul := fun n m ↦ (n : ℤ) * m nsmul_zero := Int.zero_mul nsmul_succ := fun n m ↦ show (n + 1 : ℤ) * m = m + n * m by rw [Int.add_mul, Int.add_comm, Int.one_mul] example (n : ℕ) (m : ℤ) : SMul.smul (self := mySMul) n m = n * m := rfl
-
-
-
@@ -0,0 +1,114 @@import Mathlib.Topology.Instances.Real def isMonoidHom₁ [Monoid G] [Monoid H] (f : G → H) : Prop := f 1 = 1 ∧ ∀ g g', f (g * g') = f g * f g' structure isMonoidHom₂ [Monoid G] [Monoid H] (f : G → H) : Prop where map_one : f 1 = 1 map_mul : ∀ g g', f (g * g') = f g * f g' example : Continuous (id : ℝ → ℝ) := continuous_id @[ext] structure MonoidHom₁ (G H : Type) [Monoid G] [Monoid H] where toFun : G → H map_one : toFun 1 = 1 map_mul : ∀ g g', toFun (g * g') = toFun g * toFun g' instance [Monoid G] [Monoid H] : CoeFun (MonoidHom₁ G H) (fun _ ↦ G → H) where coe := MonoidHom₁.toFun attribute [coe] MonoidHom₁.toFun example [Monoid G] [Monoid H] (f : MonoidHom₁ G H) : f 1 = 1 := f.map_one @[ext] structure AddMonoidHom₁ (G H : Type) [AddMonoid G] [AddMonoid H] where toFun : G → H map_zero : toFun 0 = 0 map_add : ∀ g g', toFun (g + g') = toFun g + toFun g' instance [AddMonoid G] [AddMonoid H] : CoeFun (AddMonoidHom₁ G H) (fun _ ↦ G → H) where coe := AddMonoidHom₁.toFun attribute [coe] AddMonoidHom₁.toFun @[ext] structure RingHom₁ (R S : Type) [Ring R] [Ring S] extends MonoidHom₁ R S, AddMonoidHom₁ R S class MonoidHomClass₁ (F : Type) (M N : Type) [Monoid M] [Monoid N] where toFun : F → M → N map_one : ∀ f : F, toFun f 1 = 1 map_mul : ∀ f g g', toFun f (g * g') = toFun f g * toFun f g' def badInst [Monoid M] [Monoid N] [MonoidHomClass₁ F M N] : CoeFun F (fun _ ↦ M → N) where coe := MonoidHomClass₁.toFun class MonoidHomClass₂ (F : Type) (M N : outParam Type) [Monoid M] [Monoid N] where toFun : F → M → N map_one : ∀ f : F, toFun f 1 = 1 map_mul : ∀ f g g', toFun f (g * g') = toFun f g * toFun f g' instance [Monoid M] [Monoid N] [MonoidHomClass₂ F M N] : CoeFun F (fun _ ↦ M → N) where coe := MonoidHomClass₂.toFun attribute [coe] MonoidHomClass₂.toFun instance (M N : Type) [Monoid M] [Monoid N] : MonoidHomClass₂ (MonoidHom₁ M N) M N where toFun := MonoidHom₁.toFun map_one := fun f ↦ f.map_one map_mul := fun f ↦ f.map_mul instance (R S : Type) [Ring R] [Ring S] : MonoidHomClass₂ (RingHom₁ R S) R S where toFun := fun f ↦ f.toMonoidHom₁.toFun map_one := fun f ↦ f.toMonoidHom₁.map_one map_mul := fun f ↦ f.toMonoidHom₁.map_mul lemma map_inv_of_inv [Monoid M] [Monoid N] [MonoidHomClass₂ F M N] (f : F) {m m' : M} (h : m*m' = 1) : f m * f m' = 1 := by rw [← MonoidHomClass₂.map_mul, h, MonoidHomClass₂.map_one] example [Monoid M] [Monoid N] (f : MonoidHom₁ M N) {m m' : M} (h : m*m' = 1) : f m * f m' = 1 := map_inv_of_inv f h example [Ring R] [Ring S] (f : RingHom₁ R S) {r r' : R} (h : r*r' = 1) : f r * f r' = 1 := map_inv_of_inv f h class MonoidHomClass₃ (F : Type) (M N : outParam Type) [Monoid M] [Monoid N] extends FunLike F M (fun _ ↦ N) where map_one : ∀ f : F, f 1 = 1 map_mul : ∀ (f : F) g g', f (g * g') = f g * f g' instance (M N : Type) [Monoid M] [Monoid N] : MonoidHomClass₃ (MonoidHom₁ M N) M N where coe := MonoidHom₁.toFun coe_injective' := MonoidHom₁.ext map_one := MonoidHom₁.map_one map_mul := MonoidHom₁.map_mul @[ext] structure OrderPresHom (α β : Type) [LE α] [LE β] where toFun : α → β le_of_le : ∀ a a', a ≤ a' → toFun a ≤ toFun a' @[ext] structure OrderPresMonoidHom (M N : Type) [Monoid M] [LE M] [Monoid N] [LE N] extends MonoidHom₁ M N, OrderPresHom M N class OrderPresHomClass (F : Type) (α β : outParam Type) [LE α] [LE β] instance (α β : Type) [LE α] [LE β] : OrderPresHomClass (OrderPresHom α β) α β where instance (α β : Type) [LE α] [Monoid α] [LE β] [Monoid β] : OrderPresHomClass (OrderPresMonoidHom α β) α β where instance (α β : Type) [LE α] [Monoid α] [LE β] [Monoid β] : MonoidHomClass₃ (OrderPresMonoidHom α β) α β := sorry
-
-
-
@@ -0,0 +1,88 @@import Mathlib.GroupTheory.QuotientGroup @[ext] structure Submonoid₁ (M : Type) [Monoid M] where /-- The carrier of a submonoid. -/ carrier : Set M /-- The product of two elements of a submonoid belongs to the submonoid. -/ mul_mem {a b} : a ∈ carrier → b ∈ carrier → a * b ∈ carrier /-- The unit element belongs to the submonoid. -/ one_mem : 1 ∈ carrier /-- Submonoids in `M` can be seen as sets in `M`. -/ instance [Monoid M] : SetLike (Submonoid₁ M) M where coe := Submonoid₁.carrier coe_injective' := Submonoid₁.ext example [Monoid M] (N : Submonoid₁ M) : 1 ∈ N := N.one_mem example [Monoid M] (N : Submonoid₁ M) (α : Type) (f : M → α) := f '' N example [Monoid M] (N : Submonoid₁ M) (x : N) : (x : M) ∈ N := x.property instance SubMonoid₁Monoid [Monoid M] (N : Submonoid₁ M) : Monoid N where mul := fun x y ↦ ⟨x*y, N.mul_mem x.property y.property⟩ mul_assoc := fun x y z ↦ SetCoe.ext (mul_assoc (x : M) y z) one := ⟨1, N.one_mem⟩ one_mul := fun x ↦ SetCoe.ext (one_mul (x : M)) mul_one := fun x ↦ SetCoe.ext (mul_one (x : M)) example [Monoid M] (N : Submonoid₁ M) : Monoid N where mul := fun ⟨x, hx⟩ ⟨y, hy⟩ ↦ ⟨x*y, N.mul_mem hx hy⟩ mul_assoc := fun ⟨x, _⟩ ⟨y, _⟩ ⟨z, _⟩ ↦ SetCoe.ext (mul_assoc x y z) one := ⟨1, N.one_mem⟩ one_mul := fun ⟨x, _⟩ ↦ SetCoe.ext (one_mul x) mul_one := fun ⟨x, _⟩ ↦ SetCoe.ext (mul_one x) class SubmonoidClass₁ (S : Type) (M : Type) [Monoid M] [SetLike S M] : Prop where mul_mem : ∀ (s : S) {a b : M}, a ∈ s → b ∈ s → a * b ∈ s one_mem : ∀ s : S, 1 ∈ s instance [Monoid M] : SubmonoidClass₁ (Submonoid₁ M) M where mul_mem := Submonoid₁.mul_mem one_mem := Submonoid₁.one_mem instance [Monoid M] : Inf (Submonoid₁ M) := ⟨fun S₁ S₂ => { carrier := S₁ ∩ S₂ one_mem := ⟨S₁.one_mem, S₂.one_mem⟩ mul_mem := fun ⟨hx, hx'⟩ ⟨hy, hy'⟩ ↦ ⟨S₁.mul_mem hx hy, S₂.mul_mem hx' hy'⟩ }⟩ example [Monoid M] (N P : Submonoid₁ M) : Submonoid₁ M := N ⊓ P def Submonoid.Setoid [CommMonoid M] (N : Submonoid M) : Setoid M where r := fun x y ↦ ∃ w ∈ N, ∃ z ∈ N, x*w = y*z iseqv := { refl := fun x ↦ ⟨1, N.one_mem, 1, N.one_mem, rfl⟩ symm := fun ⟨w, hw, z, hz, h⟩ ↦ ⟨z, hz, w, hw, h.symm⟩ trans := by sorry } instance [CommMonoid M] : HasQuotient M (Submonoid M) where quotient' := fun N ↦ Quotient N.Setoid def QuotientMonoid.mk [CommMonoid M] (N : Submonoid M) : M → M ⧸ N := Quotient.mk N.Setoid instance [CommMonoid M] (N : Submonoid M) : Monoid (M ⧸ N) where mul := Quotient.map₂' (· * ·) (by sorry ) mul_assoc := by sorry one := QuotientMonoid.mk N 1 one_mul := by sorry mul_one := by sorry
-
-
-
@@ -0,0 +1,348 @@import Mathlib.Algebra.BigOperators.Ring import Mathlib.Data.Real.Basic class One₁ (α : Type) where /-- The element one -/ one : α #check One₁.one -- One₁.one {α : Type} [self : One₁ α] : α @[class] structure One₂ (α : Type) where /-- The element one -/ one : α #check One₂.one example (α : Type) [One₁ α] : α := One₁.one example (α : Type) [One₁ α] := (One₁.one : α) @[inherit_doc] notation "𝟙" => One₁.one example {α : Type} [One₁ α] : α := 𝟙 example {α : Type} [One₁ α] : (𝟙 : α) = 𝟙 := rfl class Dia₁ (α : Type) where dia : α → α → α infixl:70 " ⋄ " => Dia₁.dia class Semigroup₁ (α : Type) where toDia₁ : Dia₁ α /-- Diamond is associative -/ dia_assoc : ∀ a b c : α, a ⋄ b ⋄ c = a ⋄ (b ⋄ c) attribute [instance] Semigroup₁.toDia₁ example {α : Type} [Semigroup₁ α] (a b : α) : α := a ⋄ b class Semigroup₂ (α : Type) extends Dia₁ α where /-- Diamond is associative -/ dia_assoc : ∀ a b c : α, a ⋄ b ⋄ c = a ⋄ (b ⋄ c) example {α : Type} [Semigroup₂ α] (a b : α) : α := a ⋄ b class DiaOneClass₁ (α : Type) extends One₁ α, Dia₁ α where /-- One is a left neutral element for diamond. -/ one_dia : ∀ a : α, 𝟙 ⋄ a = a /-- One is a right neutral element for diamond -/ dia_one : ∀ a : α, a ⋄ 𝟙 = a set_option trace.Meta.synthInstance true in example {α : Type} [DiaOneClass₁ α] (a b : α) : Prop := a ⋄ b = 𝟙 class Monoid₁ (α : Type) extends Semigroup₁ α, DiaOneClass₁ α class Monoid₂ (α : Type) where toSemigroup₁ : Semigroup₁ α toDiaOneClass₁ : DiaOneClass₁ α example {α : Type} [Monoid₁ α] : (Monoid₁.toSemigroup₁.toDia₁.dia : α → α → α) = Monoid₁.toDiaOneClass₁.toDia₁.dia := rfl /- Monoid₂.mk {α : Type} (toSemigroup₁ : Semigroup₁ α) (toDiaOneClass₁ : DiaOneClass₁ α) : Monoid₂ α -/ #check Monoid₂.mk /- Monoid₁.mk {α : Type} [toSemigroup₁ : Semigroup₁ α] [toOne₁ : One₁ α] (one_dia : ∀ (a : α), 𝟙 ⋄ a = a) (dia_one : ∀ (a : α), a ⋄ 𝟙 = a) : Monoid₁ α -/ #check Monoid₁.mk #check Monoid₁.toSemigroup₁ #check Monoid₁.toDiaOneClass₁ class Inv₁ (α : Type) where /-- The inversion function -/ inv : α → α @[inherit_doc] postfix:max "⁻¹" => Inv₁.inv class Group₁ (G : Type) extends Monoid₁ G, Inv G where inv_dia : ∀ a : G, a⁻¹ ⋄ a = 𝟙 lemma left_inv_eq_right_inv₁ {M : Type} [Monoid₁ M] {a b c : M} (hba : b ⋄ a = 𝟙) (hac : a ⋄ c = 𝟙) : b = c := by rw [← DiaOneClass₁.one_dia c, ← hba, Semigroup₁.dia_assoc, hac, DiaOneClass₁.dia_one b] export DiaOneClass₁ (one_dia dia_one) export Semigroup₁ (dia_assoc) export Group₁ (inv_dia) example {M : Type} [Monoid₁ M] {a b c : M} (hba : b ⋄ a = 𝟙) (hac : a ⋄ c = 𝟙) : b = c := by rw [← one_dia c, ← hba, dia_assoc, hac, dia_one b] lemma inv_eq_of_dia [Group₁ G] {a b : G} (h : a ⋄ b = 𝟙) : a⁻¹ = b := left_inv_eq_right_inv₁ (inv_dia a) h lemma dia_inv [Group₁ G] (a : G) : a ⋄ a⁻¹ = 𝟙 := by rw [← inv_dia a⁻¹, inv_eq_of_dia (inv_dia a)] class AddSemigroup₃ (α : Type) extends Add α where /-- Multiplication is associative -/ add_assoc₃ : ∀ a b c : α, a + b + c = a + (b + c) @[to_additive AddSemigroup₃] class Semigroup₃ (α : Type) extends Mul α where /-- Multiplication is associative -/ mul_assoc₃ : ∀ a b c : α, a * b * c = a * (b * c) class AddMonoid₃ (α : Type) extends AddSemigroup₃ α, AddZeroClass α @[to_additive AddMonoid₃] class Monoid₃ (α : Type) extends Semigroup₃ α, MulOneClass α attribute [to_additive existing] Monoid₃.toMulOneClass export Semigroup₃ (mul_assoc₃) export AddSemigroup₃ (add_assoc₃) whatsnew in @[to_additive] lemma left_inv_eq_right_inv' {M : Type} [Monoid₃ M] {a b c : M} (hba : b * a = 1) (hac : a * c = 1) : b = c := by rw [← one_mul c, ← hba, mul_assoc₃, hac, mul_one b] #check left_neg_eq_right_neg' class AddCommSemigroup₃ (α : Type) extends AddSemigroup₃ α where add_comm : ∀ a b : α, a + b = b + a @[to_additive AddCommSemigroup₃] class CommSemigroup₃ (α : Type) extends Semigroup₃ α where mul_comm : ∀ a b : α, a * b = b * a class AddCommMonoid₃ (α : Type) extends AddMonoid₃ α, AddCommSemigroup₃ α @[to_additive AddCommMonoid₃] class CommMonoid₃ (α : Type) extends Monoid₃ α, CommSemigroup₃ α class AddGroup₃ (G : Type) extends AddMonoid₃ G, Neg G where neg_add : ∀ a : G, -a + a = 0 @[to_additive AddGroup₃] class Group₃ (G : Type) extends Monoid₃ G, Inv G where inv_mul : ∀ a : G, a⁻¹ * a = 1 attribute [simp] Group₃.inv_mul AddGroup₃.neg_add @[to_additive] lemma inv_eq_of_mul [Group₃ G] {a b : G} (h : a * b = 1) : a⁻¹ = b := left_inv_eq_right_inv' (Group₃.inv_mul a) h @[to_additive (attr := simp)] lemma Group₃.mul_inv {G : Type} [Group₃ G] {a : G} : a * a⁻¹ = 1 := by rw [← inv_mul a⁻¹, inv_eq_of_mul (inv_mul a)] @[to_additive] lemma mul_left_cancel₃ {G : Type} [Group₃ G] {a b c : G} (h : a * b = a * c) : b = c := by simpa [← mul_assoc₃] using congr_arg (a⁻¹ * ·) h @[to_additive] lemma mul_right_cancel₃ {G : Type} [Group₃ G] {a b c : G} (h : b*a = c*a) : b = c := by simpa [mul_assoc₃] using congr_arg (· * a⁻¹) h class AddCommGroup₃ (G : Type) extends AddGroup₃ G, AddCommMonoid₃ G @[to_additive AddCommGroup₃] class CommGroup₃ (G : Type) extends Group₃ G, CommMonoid₃ G class Ring₃ (R : Type) extends AddGroup₃ R, Monoid₃ R, MulZeroClass R where /-- Multiplication is left distributive over addition -/ left_distrib : ∀ a b c : R, a * (b + c) = a * b + a * c /-- Multiplication is right distributive over addition -/ right_distrib : ∀ a b c : R, (a + b) * c = a * c + b * c instance {R : Type} [Ring₃ R] : AddCommGroup₃ R := { Ring₃.toAddGroup₃ with add_comm := by intro a b have : a + (a + b + b) = a + (b + a + b) := calc a + (a + b + b) = (a + a) + (b + b) := by simp [add_assoc₃, add_assoc₃] _ = (1 * a + 1 * a) + (1 * b + 1 * b) := by simp _ = (1 + 1) * a + (1 + 1) * b := by simp [Ring₃.right_distrib] _ = (1 + 1) * (a + b) := by simp [Ring₃.left_distrib] _ = 1 * (a + b) + 1 * (a + b) := by simp [Ring₃.right_distrib] _ = (a + b) + (a + b) := by simp _ = a + (b + a + b) := by simp [add_assoc₃] exact add_right_cancel₃ (add_left_cancel₃ this) } instance : Ring₃ ℤ where add := (· + ·) add_assoc₃ := add_assoc zero := 0 zero_add := by simp add_zero := by simp neg := (- ·) neg_add := by simp mul := (· * ·) mul_assoc₃ := mul_assoc one := 1 one_mul := by simp mul_one := by simp zero_mul := by simp mul_zero := by simp left_distrib := Int.mul_add right_distrib := Int.add_mul class LE₁ (α : Type) where /-- The Less-or-Equal relation. -/ le : α → α → Prop @[inherit_doc] infix:50 " ≤₁ " => LE₁.le class Preorder₁ (α : Type) extends LE₁ α where le_refl : ∀ a : α, a ≤₁ a le_trans : ∀ a b c : α, a ≤₁ b → b ≤₁ c → a ≤₁ c class PartialOrder₁ (α : Type) extends Preorder₁ α where le_antisymm : ∀ a b : α, a ≤₁ b → b ≤₁ a → a = b class OrderedCommMonoid₁ (α : Type) extends PartialOrder₁ α, CommMonoid₃ α where mul_of_le : ∀ a b : α, a ≤₁ b → ∀ c : α, c * a ≤₁ c * b instance : OrderedCommMonoid₁ ℕ where le := (· ≤ ·) le_refl := fun _ ↦ le_rfl le_trans := fun _ _ _ ↦ le_trans le_antisymm := fun _ _ ↦ le_antisymm mul := (· * ·) mul_assoc₃ := mul_assoc one := 1 one_mul := one_mul mul_one := mul_one mul_comm := mul_comm mul_of_le := fun _ _ h c ↦ Nat.mul_le_mul_left c h class SMul₃ (α : Type) (β : Type) where /-- Scalar multiplication -/ smul : α → β → β infixr:73 " • " => SMul₃.smul class Module₁ (R : Type) [Ring₃ R] (M : Type) [AddCommGroup₃ M] extends SMul₃ R M where zero_smul : ∀ m : M, (0 : R) • m = 0 one_smul : ∀ m : M, (1 : R) • m = m mul_smul : ∀ (a b : R) (m : M), (a * b) • m = a • b • m add_smul : ∀ (a b : R) (m : M), (a + b) • m = a • m + b • m smul_add : ∀ (a : R) (m n : M), a • (m + n) = a • m + a • n instance selfModule (R : Type) [Ring₃ R] : Module₁ R R where smul := fun r s ↦ r*s zero_smul := zero_mul one_smul := one_mul mul_smul := mul_assoc₃ add_smul := Ring₃.right_distrib smul_add := Ring₃.left_distrib def nsmul₁ [Zero M] [Add M] : ℕ → M → M | 0, _ => 0 | n + 1, a => a + nsmul₁ n a def zsmul₁ {M : Type _} [Zero M] [Add M] [Neg M] : ℤ → M → M | Int.ofNat n, a => nsmul₁ n a | Int.negSucc n, a => -nsmul₁ n.succ a instance abGrpModule (A : Type) [AddCommGroup₃ A] : Module₁ ℤ A where smul := zsmul₁ zero_smul := sorry one_smul := sorry mul_smul := sorry add_smul := sorry smul_add := sorry #synth Module₁ ℤ ℤ -- abGrpModule ℤ class AddMonoid₄ (M : Type) extends AddSemigroup₃ M, AddZeroClass M where /-- Multiplication by a natural number. -/ nsmul : ℕ → M → M := nsmul₁ /-- Multiplication by `(0 : ℕ)` gives `0`. -/ nsmul_zero : ∀ x, nsmul 0 x = 0 := by intros; rfl /-- Multiplication by `(n + 1 : ℕ)` behaves as expected. -/ nsmul_succ : ∀ (n : ℕ) (x), nsmul (n + 1) x = x + nsmul n x := by intros; rfl instance mySMul {M : Type} [AddMonoid₄ M] : SMul ℕ M := ⟨AddMonoid₄.nsmul⟩ instance (M N : Type) [AddMonoid₄ M] [AddMonoid₄ N] : AddMonoid₄ (M × N) where add := fun p q ↦ (p.1 + q.1, p.2 + q.2) add_assoc₃ := fun a b c ↦ by ext <;> apply add_assoc₃ zero := (0, 0) zero_add := fun a ↦ by ext <;> apply zero_add add_zero := fun a ↦ by ext <;> apply add_zero instance : AddMonoid₄ ℤ where add := (· + ·) add_assoc₃ := Int.add_assoc zero := 0 zero_add := Int.zero_add add_zero := Int.add_zero nsmul := fun n m ↦ (n : ℤ) * m nsmul_zero := Int.zero_mul nsmul_succ := fun n m ↦ show (n + 1 : ℤ) * m = m + n * m by rw [Int.add_mul, Int.add_comm, Int.one_mul] example (n : ℕ) (m : ℤ) : SMul.smul (self := mySMul) n m = n * m := rfl class LT₁ (α : Type) where /-- The Less-Than relation -/ lt : α → α → Prop @[inherit_doc] infix:50 " <₁ " => LT₁.lt class PreOrder₂ (α : Type) extends LE₁ α, LT₁ α where le_refl : ∀ a : α, a ≤₁ a le_trans : ∀ a b c : α, a ≤₁ b → b ≤₁ c → a ≤₁ c lt := fun a b => a ≤₁ b ∧ ¬b ≤₁ a lt_iff_le_not_le : ∀ a b : α, a <₁ b ↔ a ≤₁ b ∧ ¬b ≤₁ a := by intros; rfl
-
-
-
@@ -0,0 +1,126 @@import Mathlib.Topology.Instances.Real def isMonoidHom₁ [Monoid G] [Monoid H] (f : G → H) : Prop := f 1 = 1 ∧ ∀ g g', f (g * g') = f g * f g' structure isMonoidHom₂ [Monoid G] [Monoid H] (f : G → H) : Prop where map_one : f 1 = 1 map_mul : ∀ g g', f (g * g') = f g * f g' example : Continuous (id : ℝ → ℝ) := continuous_id @[ext] structure MonoidHom₁ (G H : Type) [Monoid G] [Monoid H] where toFun : G → H map_one : toFun 1 = 1 map_mul : ∀ g g', toFun (g * g') = toFun g * toFun g' instance [Monoid G] [Monoid H] : CoeFun (MonoidHom₁ G H) (fun _ ↦ G → H) where coe := MonoidHom₁.toFun attribute [coe] MonoidHom₁.toFun example [Monoid G] [Monoid H] (f : MonoidHom₁ G H) : f 1 = 1 := f.map_one @[ext] structure AddMonoidHom₁ (G H : Type) [AddMonoid G] [AddMonoid H] where toFun : G → H map_zero : toFun 0 = 0 map_add : ∀ g g', toFun (g + g') = toFun g + toFun g' instance [AddMonoid G] [AddMonoid H] : CoeFun (AddMonoidHom₁ G H) (fun _ ↦ G → H) where coe := AddMonoidHom₁.toFun attribute [coe] AddMonoidHom₁.toFun @[ext] structure RingHom₁ (R S : Type) [Ring R] [Ring S] extends MonoidHom₁ R S, AddMonoidHom₁ R S class MonoidHomClass₁ (F : Type) (M N : Type) [Monoid M] [Monoid N] where toFun : F → M → N map_one : ∀ f : F, toFun f 1 = 1 map_mul : ∀ f g g', toFun f (g * g') = toFun f g * toFun f g' def badInst [Monoid M] [Monoid N] [MonoidHomClass₁ F M N] : CoeFun F (fun _ ↦ M → N) where coe := MonoidHomClass₁.toFun class MonoidHomClass₂ (F : Type) (M N : outParam Type) [Monoid M] [Monoid N] where toFun : F → M → N map_one : ∀ f : F, toFun f 1 = 1 map_mul : ∀ f g g', toFun f (g * g') = toFun f g * toFun f g' instance [Monoid M] [Monoid N] [MonoidHomClass₂ F M N] : CoeFun F (fun _ ↦ M → N) where coe := MonoidHomClass₂.toFun attribute [coe] MonoidHomClass₂.toFun instance (M N : Type) [Monoid M] [Monoid N] : MonoidHomClass₂ (MonoidHom₁ M N) M N where toFun := MonoidHom₁.toFun map_one := fun f ↦ f.map_one map_mul := fun f ↦ f.map_mul instance (R S : Type) [Ring R] [Ring S] : MonoidHomClass₂ (RingHom₁ R S) R S where toFun := fun f ↦ f.toMonoidHom₁.toFun map_one := fun f ↦ f.toMonoidHom₁.map_one map_mul := fun f ↦ f.toMonoidHom₁.map_mul lemma map_inv_of_inv [Monoid M] [Monoid N] [MonoidHomClass₂ F M N] (f : F) {m m' : M} (h : m*m' = 1) : f m * f m' = 1 := by rw [← MonoidHomClass₂.map_mul, h, MonoidHomClass₂.map_one] example [Monoid M] [Monoid N] (f : MonoidHom₁ M N) {m m' : M} (h : m*m' = 1) : f m * f m' = 1 := map_inv_of_inv f h example [Ring R] [Ring S] (f : RingHom₁ R S) {r r' : R} (h : r*r' = 1) : f r * f r' = 1 := map_inv_of_inv f h class MonoidHomClass₃ (F : Type) (M N : outParam Type) [Monoid M] [Monoid N] extends FunLike F M (fun _ ↦ N) where map_one : ∀ f : F, f 1 = 1 map_mul : ∀ (f : F) g g', f (g * g') = f g * f g' instance (M N : Type) [Monoid M] [Monoid N] : MonoidHomClass₃ (MonoidHom₁ M N) M N where coe := MonoidHom₁.toFun coe_injective' := MonoidHom₁.ext map_one := MonoidHom₁.map_one map_mul := MonoidHom₁.map_mul @[ext] structure OrderPresHom (α β : Type) [LE α] [LE β] where toFun : α → β le_of_le : ∀ a a', a ≤ a' → toFun a ≤ toFun a' @[ext] structure OrderPresMonoidHom (M N : Type) [Monoid M] [LE M] [Monoid N] [LE N] extends MonoidHom₁ M N, OrderPresHom M N class OrderPresHomClass (F : Type) (α β : outParam Type) [LE α] [LE β] extends FunLike F α (fun _ ↦ β) where le_of_le : ∀ (f : F) a a', a ≤ a' → f a ≤ f a' instance (α β : Type) [LE α] [LE β] : OrderPresHomClass (OrderPresHom α β) α β where coe := OrderPresHom.toFun coe_injective' := OrderPresHom.ext le_of_le := OrderPresHom.le_of_le instance (α β : Type) [LE α] [Monoid α] [LE β] [Monoid β] : OrderPresHomClass (OrderPresMonoidHom α β) α β where coe := fun f ↦ f.toOrderPresHom.toFun coe_injective' := OrderPresMonoidHom.ext le_of_le := fun f ↦ f.toOrderPresHom.le_of_le instance (α β : Type) [LE α] [Monoid α] [LE β] [Monoid β] : MonoidHomClass₃ (OrderPresMonoidHom α β) α β where coe := fun f ↦ f.toOrderPresHom.toFun coe_injective' := OrderPresMonoidHom.ext map_one := fun f ↦ f.toMonoidHom₁.map_one map_mul := fun f ↦ f.toMonoidHom₁.map_mul
-
-
-
@@ -0,0 +1,126 @@import Mathlib.GroupTheory.QuotientGroup @[ext] structure Submonoid₁ (M : Type) [Monoid M] where /-- The carrier of a submonoid. -/ carrier : Set M /-- The product of two elements of a submonoid belongs to the submonoid. -/ mul_mem {a b} : a ∈ carrier → b ∈ carrier → a * b ∈ carrier /-- The unit element belongs to the submonoid. -/ one_mem : 1 ∈ carrier /-- Submonoids in `M` can be seen as sets in `M`. -/ instance [Monoid M] : SetLike (Submonoid₁ M) M where coe := Submonoid₁.carrier coe_injective' := Submonoid₁.ext example [Monoid M] (N : Submonoid₁ M) : 1 ∈ N := N.one_mem example [Monoid M] (N : Submonoid₁ M) (α : Type) (f : M → α) := f '' N example [Monoid M] (N : Submonoid₁ M) (x : N) : (x : M) ∈ N := x.property instance SubMonoid₁Monoid [Monoid M] (N : Submonoid₁ M) : Monoid N where mul := fun x y ↦ ⟨x*y, N.mul_mem x.property y.property⟩ mul_assoc := fun x y z ↦ SetCoe.ext (mul_assoc (x : M) y z) one := ⟨1, N.one_mem⟩ one_mul := fun x ↦ SetCoe.ext (one_mul (x : M)) mul_one := fun x ↦ SetCoe.ext (mul_one (x : M)) example [Monoid M] (N : Submonoid₁ M) : Monoid N where mul := fun ⟨x, hx⟩ ⟨y, hy⟩ ↦ ⟨x*y, N.mul_mem hx hy⟩ mul_assoc := fun ⟨x, _⟩ ⟨y, _⟩ ⟨z, _⟩ ↦ SetCoe.ext (mul_assoc x y z) one := ⟨1, N.one_mem⟩ one_mul := fun ⟨x, _⟩ ↦ SetCoe.ext (one_mul x) mul_one := fun ⟨x, _⟩ ↦ SetCoe.ext (mul_one x) class SubmonoidClass₁ (S : Type) (M : Type) [Monoid M] [SetLike S M] : Prop where mul_mem : ∀ (s : S) {a b : M}, a ∈ s → b ∈ s → a * b ∈ s one_mem : ∀ s : S, 1 ∈ s instance [Monoid M] : SubmonoidClass₁ (Submonoid₁ M) M where mul_mem := Submonoid₁.mul_mem one_mem := Submonoid₁.one_mem @[ext] structure Subgroup₁ (G : Type) [Group G] extends Submonoid₁ G where /-- The inverse of an element of a subgroup belongs to the subgroup. -/ inv_mem {a} : a ∈ carrier → a⁻¹ ∈ carrier /-- Subgroups in `M` can be seen as sets in `M`. -/ instance [Group G] : SetLike (Subgroup₁ G) G where coe := fun H ↦ H.toSubmonoid₁.carrier coe_injective' := Subgroup₁.ext instance [Group G] (H : Subgroup₁ G) : Group H := { SubMonoid₁Monoid H.toSubmonoid₁ with inv := fun x ↦ ⟨x⁻¹, H.inv_mem x.property⟩ mul_left_inv := fun x ↦ SetCoe.ext (mul_left_inv (x : G)) } class SubgroupClass₁ (S : Type _) (G : Type) [Group G] [SetLike S G] extends SubmonoidClass₁ S G : Prop where inv_mem : ∀ (s : S) {a : G}, a ∈ s → a⁻¹ ∈ s instance [Group G] : SubmonoidClass₁ (Subgroup₁ G) G where mul_mem := fun H ↦ H.toSubmonoid₁.mul_mem one_mem := fun H ↦ H.toSubmonoid₁.one_mem instance [Group G] : SubgroupClass₁ (Subgroup₁ G) G := { (inferInstance : SubmonoidClass₁ (Subgroup₁ G) G) with inv_mem := Subgroup₁.inv_mem } instance [Monoid M] : Inf (Submonoid₁ M) := ⟨fun S₁ S₂ => { carrier := S₁ ∩ S₂ one_mem := ⟨S₁.one_mem, S₂.one_mem⟩ mul_mem := fun ⟨hx, hx'⟩ ⟨hy, hy'⟩ ↦ ⟨S₁.mul_mem hx hy, S₂.mul_mem hx' hy'⟩ }⟩ example [Monoid M] (N P : Submonoid₁ M) : Submonoid₁ M := N ⊓ P def Submonoid.Setoid [CommMonoid M] (N : Submonoid M) : Setoid M where r := fun x y ↦ ∃ w ∈ N, ∃ z ∈ N, x*w = y*z iseqv := { refl := fun x ↦ ⟨1, N.one_mem, 1, N.one_mem, rfl⟩ symm := fun ⟨w, hw, z, hz, h⟩ ↦ ⟨z, hz, w, hw, h.symm⟩ trans := by rintro a b c ⟨w, hw, z, hz, h⟩ ⟨w', hw', z', hz', h'⟩ refine ⟨w*w', N.mul_mem hw hw', z*z', N.mul_mem hz hz', ?_⟩ rw [← mul_assoc, h, mul_comm b, mul_assoc, h', ← mul_assoc, mul_comm z, mul_assoc] } instance [CommMonoid M] : HasQuotient M (Submonoid M) where quotient' := fun N ↦ Quotient N.Setoid def QuotientMonoid.mk [CommMonoid M] (N : Submonoid M) : M → M ⧸ N := Quotient.mk N.Setoid instance [CommMonoid M] (N : Submonoid M) : Monoid (M ⧸ N) where mul := Quotient.map₂' (· * ·) (by rintro a₁ b₁ ⟨w, hw, z, hz, ha⟩ a₂ b₂ ⟨w', hw', z', hz', hb⟩ refine ⟨w*w', N.mul_mem hw hw', z*z', N.mul_mem hz hz', ?_⟩ rw [mul_comm w, ← mul_assoc, mul_assoc a₁, hb, mul_comm, ← mul_assoc, mul_comm w, ha, mul_assoc, mul_comm z, mul_assoc b₂, mul_comm z', mul_assoc] ) mul_assoc := by rintro ⟨a⟩ ⟨b⟩ ⟨c⟩ apply Quotient.sound dsimp only rw [mul_assoc] apply @Setoid.refl M N.Setoid one := QuotientMonoid.mk N 1 one_mul := by rintro ⟨a⟩ ; apply Quotient.sound ; dsimp only ; rw [one_mul] ; apply @Setoid.refl M N.Setoid mul_one := by rintro ⟨a⟩ ; apply Quotient.sound ; dsimp only ; rw [mul_one] ; apply @Setoid.refl M N.Setoid
-
-
-
@@ -0,0 +1,105 @@import Mathlib.Topology.Instances.Real open Set Filter Topology def principal {α : Type _} (s : Set α) : Filter α where sets := { t | s ⊆ t } univ_sets := sorry sets_of_superset := sorry inter_sets := sorry example : Filter ℕ := { sets := { s | ∃ a, ∀ b, a ≤ b → b ∈ s } univ_sets := sorry sets_of_superset := sorry inter_sets := sorry } def Tendsto₁ {X Y : Type _} (f : X → Y) (F : Filter X) (G : Filter Y) := ∀ V ∈ G, f ⁻¹' V ∈ F def Tendsto₂ {X Y : Type _} (f : X → Y) (F : Filter X) (G : Filter Y) := map f F ≤ G example {X Y : Type _} (f : X → Y) (F : Filter X) (G : Filter Y) : Tendsto₂ f F G ↔ Tendsto₁ f F G := Iff.rfl #check (@Filter.map_mono : ∀ {α β} {m : α → β}, Monotone (map m)) #check (@Filter.map_map : ∀ {α β γ} {f : Filter α} {m : α → β} {m' : β → γ}, map m' (map m f) = map (m' ∘ m) f) example {X Y Z : Type _} {F : Filter X} {G : Filter Y} {H : Filter Z} {f : X → Y} {g : Y → Z} (hf : Tendsto₁ f F G) (hg : Tendsto₁ g G H) : Tendsto₁ (g ∘ f) F H := sorry variable (f : ℝ → ℝ) (x₀ y₀ : ℝ) #check comap ((↑) : ℚ → ℝ) (𝓝 x₀) #check Tendsto (f ∘ (↑)) (comap ((↑) : ℚ → ℝ) (𝓝 x₀)) (𝓝 y₀) section variable {α β γ : Type _} (F : Filter α) {m : γ → β} {n : β → α} #check (comap_comap : comap m (comap n F) = comap (n ∘ m) F) end example : 𝓝 (x₀, y₀) = 𝓝 x₀ ×ˢ 𝓝 y₀ := nhds_prod_eq #check le_inf_iff example (f : ℕ → ℝ × ℝ) (x₀ y₀ : ℝ) : Tendsto f atTop (𝓝 (x₀, y₀)) ↔ Tendsto (Prod.fst ∘ f) atTop (𝓝 x₀) ∧ Tendsto (Prod.snd ∘ f) atTop (𝓝 y₀) := sorry example (x₀ : ℝ) : HasBasis (𝓝 x₀) (fun ε : ℝ => 0 < ε) fun ε => Ioo (x₀ - ε) (x₀ + ε) := nhds_basis_Ioo_pos x₀ example (u : ℕ → ℝ) (x₀ : ℝ) : Tendsto u atTop (𝓝 x₀) ↔ ∀ ε > 0, ∃ N, ∀ n ≥ N, u n ∈ Ioo (x₀ - ε) (x₀ + ε) := by have : atTop.HasBasis (fun _ : ℕ => True) Ici := atTop_basis rw [this.tendsto_iff (nhds_basis_Ioo_pos x₀)] simp example (P Q : ℕ → Prop) (hP : ∀ᶠ n in atTop, P n) (hQ : ∀ᶠ n in atTop, Q n) : ∀ᶠ n in atTop, P n ∧ Q n := hP.and hQ example (u v : ℕ → ℝ) (h : ∀ᶠ n in atTop, u n = v n) (x₀ : ℝ) : Tendsto u atTop (𝓝 x₀) ↔ Tendsto v atTop (𝓝 x₀) := tendsto_congr' h example (u v : ℕ → ℝ) (h : u =ᶠ[atTop] v) (x₀ : ℝ) : Tendsto u atTop (𝓝 x₀) ↔ Tendsto v atTop (𝓝 x₀) := tendsto_congr' h #check @eventually_of_forall #check @Eventually.mono #check @Eventually.and example (P Q R : ℕ → Prop) (hP : ∀ᶠ n in atTop, P n) (hQ : ∀ᶠ n in atTop, Q n) (hR : ∀ᶠ n in atTop, P n ∧ Q n → R n) : ∀ᶠ n in atTop, R n := by apply (hP.and (hQ.and hR)).mono rintro n ⟨h, h', h''⟩ exact h'' ⟨h, h'⟩ example (P Q R : ℕ → Prop) (hP : ∀ᶠ n in atTop, P n) (hQ : ∀ᶠ n in atTop, Q n) (hR : ∀ᶠ n in atTop, P n ∧ Q n → R n) : ∀ᶠ n in atTop, R n := by filter_upwards [hP, hQ, hR] intro n h h' h'' exact h'' ⟨h, h'⟩ #check mem_closure_iff_clusterPt #check le_principal_iff #check neBot_of_le example (u : ℕ → ℝ) (M : Set ℝ) (x : ℝ) (hux : Tendsto u atTop (𝓝 x)) (huM : ∀ᶠ n in atTop, u n ∈ M) : x ∈ closure M := sorry
-
-
-
@@ -0,0 +1,206 @@import Mathlib.Topology.Instances.Real import Mathlib.Analysis.NormedSpace.BanachSteinhaus open Set Filter open Topology Filter variable {X : Type _} [MetricSpace X] (a b c : X) #check (dist a b : ℝ) #check (dist_nonneg : 0 ≤ dist a b) #check (dist_eq_zero : dist a b = 0 ↔ a = b) #check (dist_comm a b : dist a b = dist b a) #check (dist_triangle a b c : dist a c ≤ dist a b + dist b c) -- Note the next three lines are not quoted, their purpose is to make sure those things don't get renamed while we're looking elsewhere. #check EMetricSpace #check PseudoMetricSpace #check PseudoEMetricSpace example {u : ℕ → X} {a : X} : Tendsto u atTop (𝓝 a) ↔ ∀ ε > 0, ∃ N, ∀ n ≥ N, dist (u n) a < ε := Metric.tendsto_atTop example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} : Continuous f ↔ ∀ x : X, ∀ ε > 0, ∃ δ > 0, ∀ x', dist x' x < δ → dist (f x') (f x) < ε := Metric.continuous_iff example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := by continuity example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := continuous_dist.comp ((hf.comp continuous_fst).prod_mk (hf.comp continuous_snd)) example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := by apply Continuous.dist exact hf.comp continuous_fst exact hf.comp continuous_snd example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := (hf.comp continuous_fst).dist (hf.comp continuous_snd) example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := hf.fst'.dist hf.snd' example {f : ℝ → X} (hf : Continuous f) : Continuous fun x : ℝ => f (x ^ 2 + x) := sorry example {X Y : Type _} [MetricSpace X] [MetricSpace Y] (f : X → Y) (a : X) : ContinuousAt f a ↔ ∀ ε > 0, ∃ δ > 0, ∀ {x}, dist x a < δ → dist (f x) (f a) < ε := Metric.continuousAt_iff variable (r : ℝ) example : Metric.ball a r = { b | dist b a < r } := rfl example : Metric.closedBall a r = { b | dist b a ≤ r } := rfl example (hr : 0 < r) : a ∈ Metric.ball a r := Metric.mem_ball_self hr example (hr : 0 ≤ r) : a ∈ Metric.closedBall a r := Metric.mem_closedBall_self hr example (s : Set X) : IsOpen s ↔ ∀ x ∈ s, ∃ ε > 0, Metric.ball x ε ⊆ s := Metric.isOpen_iff example {s : Set X} : IsClosed s ↔ IsOpen (sᶜ) := isOpen_compl_iff.symm example {s : Set X} (hs : IsClosed s) {u : ℕ → X} (hu : Tendsto u atTop (𝓝 a)) (hus : ∀ n, u n ∈ s) : a ∈ s := hs.mem_of_tendsto hu (eventually_of_forall hus) example {s : Set X} : a ∈ closure s ↔ ∀ ε > 0, ∃ b ∈ s, a ∈ Metric.ball b ε := Metric.mem_closure_iff example {u : ℕ → X} (hu : Tendsto u atTop (𝓝 a)) {s : Set X} (hs : ∀ n, u n ∈ s) : a ∈ closure s := sorry example {x : X} {s : Set X} : s ∈ 𝓝 x ↔ ∃ ε > 0, Metric.ball x ε ⊆ s := Metric.nhds_basis_ball.mem_iff example {x : X} {s : Set X} : s ∈ 𝓝 x ↔ ∃ ε > 0, Metric.closedBall x ε ⊆ s := Metric.nhds_basis_closedBall.mem_iff example : IsCompact (Set.Icc 0 1 : Set ℝ) := isCompact_Icc example {s : Set X} (hs : IsCompact s) {u : ℕ → X} (hu : ∀ n, u n ∈ s) : ∃ a ∈ s, ∃ φ : ℕ → ℕ, StrictMono φ ∧ Tendsto (u ∘ φ) atTop (𝓝 a) := hs.tendsto_subseq hu example {s : Set X} (hs : IsCompact s) (hs' : s.Nonempty) {f : X → ℝ} (hfs : ContinuousOn f s) : ∃ x ∈ s, ∀ y ∈ s, f x ≤ f y := hs.exists_forall_le hs' hfs example {s : Set X} (hs : IsCompact s) (hs' : s.Nonempty) {f : X → ℝ} (hfs : ContinuousOn f s) : ∃ x ∈ s, ∀ y ∈ s, f y ≤ f x := hs.exists_forall_ge hs' hfs example {s : Set X} (hs : IsCompact s) : IsClosed s := hs.isClosed example {X : Type _} [MetricSpace X] [CompactSpace X] : IsCompact (univ : Set X) := isCompact_univ #check IsCompact.isClosed example {X : Type _} [MetricSpace X] {Y : Type _} [MetricSpace Y] {f : X → Y} : UniformContinuous f ↔ ∀ ε > 0, ∃ δ > 0, ∀ {a b : X}, dist a b < δ → dist (f a) (f b) < ε := Metric.uniformContinuous_iff example {X : Type _} [MetricSpace X] [CompactSpace X] {Y : Type _} [MetricSpace Y] {f : X → Y} (hf : Continuous f) : UniformContinuous f := sorry example (u : ℕ → X) : CauchySeq u ↔ ∀ ε > 0, ∃ N : ℕ, ∀ m ≥ N, ∀ n ≥ N, dist (u m) (u n) < ε := Metric.cauchySeq_iff example (u : ℕ → X) : CauchySeq u ↔ ∀ ε > 0, ∃ N : ℕ, ∀ n ≥ N, dist (u n) (u N) < ε := Metric.cauchySeq_iff' example [CompleteSpace X] (u : ℕ → X) (hu : CauchySeq u) : ∃ x, Tendsto u atTop (𝓝 x) := cauchySeq_tendsto_of_complete hu open BigOperators open Finset theorem cauchySeq_of_le_geometric_two' {u : ℕ → X} (hu : ∀ n : ℕ, dist (u n) (u (n + 1)) ≤ (1 / 2) ^ n) : CauchySeq u := by rw [Metric.cauchySeq_iff'] intro ε ε_pos obtain ⟨N, hN⟩ : ∃ N : ℕ, 1 / 2 ^ N * 2 < ε := by sorry use N intro n hn obtain ⟨k, rfl : n = N + k⟩ := le_iff_exists_add.mp hn calc dist (u (N + k)) (u N) = dist (u (N + 0)) (u (N + k)) := sorry _ ≤ ∑ i in range k, dist (u (N + i)) (u (N + (i + 1))) := sorry _ ≤ ∑ i in range k, (1 / 2 : ℝ) ^ (N + i) := sorry _ = 1 / 2 ^ N * ∑ i in range k, (1 / 2) ^ i := sorry _ ≤ 1 / 2 ^ N * 2 := sorry _ < ε := sorry open Metric example [CompleteSpace X] (f : ℕ → Set X) (ho : ∀ n, IsOpen (f n)) (hd : ∀ n, Dense (f n)) : Dense (⋂ n, f n) := by let B : ℕ → ℝ := fun n => (1 / 2) ^ n have Bpos : ∀ n, 0 < B n sorry /- Translate the density assumption into two functions `center` and `radius` associating to any n, x, δ, δpos a center and a positive radius such that `closedBall center radius` is included both in `f n` and in `closedBall x δ`. We can also require `radius ≤ (1/2)^(n+1)`, to ensure we get a Cauchy sequence later. -/ have : ∀ (n : ℕ) (x : X), ∀ δ > 0, ∃ y : X, ∃ r > 0, r ≤ B (n + 1) ∧ closedBall y r ⊆ closedBall x δ ∩ f n := by sorry choose! center radius Hpos HB Hball using this intro x rw [mem_closure_iff_nhds_basis nhds_basis_closedBall] intro ε εpos /- `ε` is positive. We have to find a point in the ball of radius `ε` around `x` belonging to all `f n`. For this, we construct inductively a sequence `F n = (c n, r n)` such that the closed ball `closedBall (c n) (r n)` is included in the previous ball and in `f n`, and such that `r n` is small enough to ensure that `c n` is a Cauchy sequence. Then `c n` converges to a limit which belongs to all the `f n`. -/ let F : ℕ → X × ℝ := fun n => Nat.recOn n (Prod.mk x (min ε (B 0))) fun n p => Prod.mk (center n p.1 p.2) (radius n p.1 p.2) let c : ℕ → X := fun n => (F n).1 let r : ℕ → ℝ := fun n => (F n).2 have rpos : ∀ n, 0 < r n := by sorry have rB : ∀ n, r n ≤ B n := by sorry have incl : ∀ n, closedBall (c (n + 1)) (r (n + 1)) ⊆ closedBall (c n) (r n) ∩ f n := by sorry have cdist : ∀ n, dist (c n) (c (n + 1)) ≤ B n := by sorry have : CauchySeq c := cauchySeq_of_le_geometric_two' cdist -- as the sequence `c n` is Cauchy in a complete space, it converges to a limit `y`. rcases cauchySeq_tendsto_of_complete this with ⟨y, ylim⟩ -- this point `y` will be the desired point. We will check that it belongs to all -- `f n` and to `ball x ε`. use y have I : ∀ n, ∀ m ≥ n, closedBall (c m) (r m) ⊆ closedBall (c n) (r n) := by sorry have yball : ∀ n, y ∈ closedBall (c n) (r n) := by sorry sorry
-
-
-
@@ -0,0 +1,155 @@import Mathlib.Topology.Instances.Real import Mathlib.Analysis.NormedSpace.BanachSteinhaus open Set Filter Topology section variable {X : Type _} [TopologicalSpace X] example : IsOpen (univ : Set X) := isOpen_univ example : IsOpen (∅ : Set X) := isOpen_empty example {ι : Type _} {s : ι → Set X} (hs : ∀ i, IsOpen <| s i) : IsOpen (⋃ i, s i) := isOpen_iUnion hs example {ι : Type _} [Fintype ι] {s : ι → Set X} (hs : ∀ i, IsOpen <| s i) : IsOpen (⋂ i, s i) := isOpen_iInter hs variable {Y : Type _} [TopologicalSpace Y] example {f : X → Y} : Continuous f ↔ ∀ s, IsOpen s → IsOpen (f ⁻¹' s) := continuous_def example {f : X → Y} {x : X} : ContinuousAt f x ↔ map f (𝓝 x) ≤ 𝓝 (f x) := Iff.rfl example {f : X → Y} {x : X} : ContinuousAt f x ↔ ∀ U ∈ 𝓝 (f x), ∀ᶠ x in 𝓝 x, f x ∈ U := Iff.rfl example {x : X} {s : Set X} : s ∈ 𝓝 x ↔ ∃ t, t ⊆ s ∧ IsOpen t ∧ x ∈ t := mem_nhds_iff example (x : X) : pure x ≤ 𝓝 x := pure_le_nhds x example (x : X) (P : X → Prop) (h : ∀ᶠ y in 𝓝 x, P y) : P x := pure_le_nhds x h example {P : X → Prop} {x : X} (h : ∀ᶠ y in 𝓝 x, P y) : ∀ᶠ y in 𝓝 x, ∀ᶠ z in 𝓝 y, P z := eventually_eventually_nhds.mpr h #check TopologicalSpace.mkOfNhds #check TopologicalSpace.nhds_mkOfNhds example {α : Type _} (n : α → Filter α) (H₀ : ∀ a, pure a ≤ n a) (H : ∀ a : α, ∀ p : α → Prop, (∀ᶠ x in n a, p x) → ∀ᶠ y in n a, ∀ᶠ x in n y, p x) : ∀ a, ∀ s ∈ n a, ∃ t ∈ n a, t ⊆ s ∧ ∀ a' ∈ t, s ∈ n a' := sorry end -- BOTH. variable {X Y : Type _} example (f : X → Y) : TopologicalSpace X → TopologicalSpace Y := TopologicalSpace.coinduced f example (f : X → Y) : TopologicalSpace Y → TopologicalSpace X := TopologicalSpace.induced f example (f : X → Y) (T_X : TopologicalSpace X) (T_Y : TopologicalSpace Y) : TopologicalSpace.coinduced f T_X ≤ T_Y ↔ T_X ≤ TopologicalSpace.induced f T_Y := coinduced_le_iff_le_induced #check coinduced_compose #check induced_compose example {T T' : TopologicalSpace X} : T ≤ T' ↔ ∀ s, T'.IsOpen s → T.IsOpen s := Iff.rfl example (T_X : TopologicalSpace X) (T_Y : TopologicalSpace Y) (f : X → Y) : Continuous f ↔ TopologicalSpace.coinduced f T_X ≤ T_Y := continuous_iff_coinduced_le example {Z : Type _} (f : X → Y) (T_X : TopologicalSpace X) (T_Z : TopologicalSpace Z) (g : Y → Z) : @Continuous Y Z (TopologicalSpace.coinduced f T_X) T_Z g ↔ @Continuous X Z T_X T_Z (g ∘ f) := by rw [continuous_iff_coinduced_le, coinduced_compose, continuous_iff_coinduced_le] example (ι : Type _) (X : ι → Type _) (T_X : ∀ i, TopologicalSpace <| X i) : (Pi.topologicalSpace : TopologicalSpace (∀ i, X i)) = ⨅ i, TopologicalSpace.induced (fun x => x i) (T_X i) := rfl example [TopologicalSpace X] [T2Space X] {u : ℕ → X} {a b : X} (ha : Tendsto u atTop (𝓝 a)) (hb : Tendsto u atTop (𝓝 b)) : a = b := tendsto_nhds_unique ha hb example [TopologicalSpace X] [RegularSpace X] (a : X) : (𝓝 a).HasBasis (fun s : Set X => s ∈ 𝓝 a ∧ IsClosed s) id := closed_nhds_basis a example [TopologicalSpace X] {x : X} : (𝓝 x).HasBasis (fun t : Set X => t ∈ 𝓝 x ∧ IsOpen t) id := nhds_basis_opens' x theorem aux {X Y A : Type _} [TopologicalSpace X] {c : A → X} {f : A → Y} {x : X} {F : Filter Y} (h : Tendsto f (comap c (𝓝 x)) F) {V' : Set Y} (V'_in : V' ∈ F) : ∃ V ∈ 𝓝 x, IsOpen V ∧ c ⁻¹' V ⊆ f ⁻¹' V' := sorry example [TopologicalSpace X] [TopologicalSpace Y] [RegularSpace Y] {A : Set X} (hA : ∀ x, x ∈ closure A) {f : A → Y} (f_cont : Continuous f) (hf : ∀ x : X, ∃ c : Y, Tendsto f (comap (↑) <| 𝓝 x) <| 𝓝 c) : ∃ φ : X → Y, Continuous φ ∧ ∀ a : A, φ a = f a := sorry #check @HasBasis.tendsto_right_iff example [TopologicalSpace X] [TopologicalSpace.FirstCountableTopology X] {s : Set X} {a : X} : a ∈ closure s ↔ ∃ u : ℕ → X, (∀ n, u n ∈ s) ∧ Tendsto u atTop (𝓝 a) := mem_closure_iff_seq_limit variable [TopologicalSpace X] example {F : Filter X} {x : X} : ClusterPt x F ↔ NeBot (𝓝 x ⊓ F) := Iff.rfl example {s : Set X} : IsCompact s ↔ ∀ (F : Filter X) [NeBot F], F ≤ 𝓟 s → ∃ a ∈ s, ClusterPt a F := Iff.rfl example [TopologicalSpace.FirstCountableTopology X] {s : Set X} {u : ℕ → X} (hs : IsCompact s) (hu : ∀ n, u n ∈ s) : ∃ a ∈ s, ∃ φ : ℕ → ℕ, StrictMono φ ∧ Tendsto (u ∘ φ) atTop (𝓝 a) := hs.tendsto_subseq hu variable [TopologicalSpace Y] example {x : X} {F : Filter X} {G : Filter Y} (H : ClusterPt x F) {f : X → Y} (hfx : ContinuousAt f x) (hf : Tendsto f F G) : ClusterPt (f x) G := ClusterPt.map H hfx hf example [TopologicalSpace Y] {f : X → Y} (hf : Continuous f) {s : Set X} (hs : IsCompact s) : IsCompact (f '' s) := by intro F F_ne F_le have map_eq : map f (𝓟 s ⊓ comap f F) = 𝓟 (f '' s) ⊓ F := by sorry have Hne : (𝓟 s ⊓ comap f F).NeBot := by sorry have Hle : 𝓟 s ⊓ comap f F ≤ 𝓟 s := inf_le_left sorry example {ι : Type _} {s : Set X} (hs : IsCompact s) (U : ι → Set X) (hUo : ∀ i, IsOpen (U i)) (hsU : s ⊆ ⋃ i, U i) : ∃ t : Finset ι, s ⊆ ⋃ i ∈ t, U i := hs.elim_finite_subcover U hUo hsU example [CompactSpace X] : IsCompact (univ : Set X) := isCompact_univ
-
-
-
@@ -0,0 +1,71 @@import Mathlib.Topology.Instances.Real open Set Filter Topology -- In the next example we could use `tauto` in each proof instead of knowing the lemmas example {α : Type _} (s : Set α) : Filter α := { sets := { t | s ⊆ t } univ_sets := subset_univ s sets_of_superset := fun hU hUV => Subset.trans hU hUV inter_sets := fun hU hV => subset_inter hU hV } example : Filter ℕ := { sets := { s | ∃ a, ∀ b, a ≤ b → b ∈ s } univ_sets := by use 42 simp sets_of_superset := by rintro U V ⟨N, hN⟩ hUV use N tauto inter_sets := by rintro U V ⟨N, hN⟩ ⟨N', hN'⟩ use max N N' intro b hb rw [max_le_iff] at hb constructor <;> tauto } def Tendsto₁ {X Y : Type _} (f : X → Y) (F : Filter X) (G : Filter Y) := ∀ V ∈ G, f ⁻¹' V ∈ F example {X Y Z : Type _} {F : Filter X} {G : Filter Y} {H : Filter Z} {f : X → Y} {g : Y → Z} (hf : Tendsto₁ f F G) (hg : Tendsto₁ g G H) : Tendsto₁ (g ∘ f) F H := calc map (g ∘ f) F = map g (map f F) := by rw [map_map] _ ≤ map g G := (map_mono hf) _ ≤ H := hg example {X Y Z : Type _} {F : Filter X} {G : Filter Y} {H : Filter Z} {f : X → Y} {g : Y → Z} (hf : Tendsto₁ f F G) (hg : Tendsto₁ g G H) : Tendsto₁ (g ∘ f) F H := by intro V hV rw [preimage_comp] apply hf apply hg exact hV example (f : ℕ → ℝ × ℝ) (x₀ y₀ : ℝ) : Tendsto f atTop (𝓝 (x₀, y₀)) ↔ Tendsto (Prod.fst ∘ f) atTop (𝓝 x₀) ∧ Tendsto (Prod.snd ∘ f) atTop (𝓝 y₀) := calc Tendsto f atTop (𝓝 (x₀, y₀)) ↔ map f atTop ≤ 𝓝 (x₀, y₀) := Iff.rfl _ ↔ map f atTop ≤ 𝓝 x₀ ×ˢ 𝓝 y₀ := by rw [nhds_prod_eq] _ ↔ map f atTop ≤ comap Prod.fst (𝓝 x₀) ⊓ comap Prod.snd (𝓝 y₀) := Iff.rfl _ ↔ map f atTop ≤ comap Prod.fst (𝓝 x₀) ∧ map f atTop ≤ comap Prod.snd (𝓝 y₀) := le_inf_iff _ ↔ map Prod.fst (map f atTop) ≤ 𝓝 x₀ ∧ map Prod.snd (map f atTop) ≤ 𝓝 y₀ := by rw [← map_le_iff_le_comap, ← map_le_iff_le_comap] _ ↔ map (Prod.fst ∘ f) atTop ≤ 𝓝 x₀ ∧ map (Prod.snd ∘ f) atTop ≤ 𝓝 y₀ := by rw [map_map, map_map] -- an alternative solution example (f : ℕ → ℝ × ℝ) (x₀ y₀ : ℝ) : Tendsto f atTop (𝓝 (x₀, y₀)) ↔ Tendsto (Prod.fst ∘ f) atTop (𝓝 x₀) ∧ Tendsto (Prod.snd ∘ f) atTop (𝓝 y₀) := by rw [nhds_prod_eq] unfold Tendsto SProd.sprod Filter.instSProd Filter.prod erw [le_inf_iff, ← map_le_iff_le_comap, map_map, ← map_le_iff_le_comap, map_map] example (u : ℕ → ℝ) (M : Set ℝ) (x : ℝ) (hux : Tendsto u atTop (𝓝 x)) (huM : ∀ᶠ n in atTop, u n ∈ M) : x ∈ closure M := mem_closure_iff_clusterPt.mpr (neBot_of_le <| le_inf hux <| le_principal_iff.mpr huM)
-
-
-
@@ -0,0 +1,371 @@import Mathlib.Topology.Instances.Real import Mathlib.Analysis.NormedSpace.BanachSteinhaus open Set Filter open Topology Filter variable {X : Type _} [MetricSpace X] (a b c : X) #check (dist a b : ℝ) #check (dist_nonneg : 0 ≤ dist a b) #check (dist_eq_zero : dist a b = 0 ↔ a = b) #check (dist_comm a b : dist a b = dist b a) #check (dist_triangle a b c : dist a c ≤ dist a b + dist b c) -- Note the next three lines are not quoted, their purpose is to make sure those things don't get renamed while we're looking elsewhere. #check EMetricSpace #check PseudoMetricSpace #check PseudoEMetricSpace example {u : ℕ → X} {a : X} : Tendsto u atTop (𝓝 a) ↔ ∀ ε > 0, ∃ N, ∀ n ≥ N, dist (u n) a < ε := Metric.tendsto_atTop example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} : Continuous f ↔ ∀ x : X, ∀ ε > 0, ∃ δ > 0, ∀ x', dist x' x < δ → dist (f x') (f x) < ε := Metric.continuous_iff example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := by continuity example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := continuous_dist.comp ((hf.comp continuous_fst).prod_mk (hf.comp continuous_snd)) example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := by apply Continuous.dist exact hf.comp continuous_fst exact hf.comp continuous_snd example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := (hf.comp continuous_fst).dist (hf.comp continuous_snd) example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := hf.fst'.dist hf.snd' example {f : ℝ → X} (hf : Continuous f) : Continuous fun x : ℝ => f (x ^ 2 + x) := sorry example {f : ℝ → X} (hf : Continuous f) : Continuous fun x : ℝ => f (x ^ 2 + x) := hf.comp <| (continuous_pow 2).add continuous_id example {X Y : Type _} [MetricSpace X] [MetricSpace Y] (f : X → Y) (a : X) : ContinuousAt f a ↔ ∀ ε > 0, ∃ δ > 0, ∀ {x}, dist x a < δ → dist (f x) (f a) < ε := Metric.continuousAt_iff variable (r : ℝ) example : Metric.ball a r = { b | dist b a < r } := rfl example : Metric.closedBall a r = { b | dist b a ≤ r } := rfl example (hr : 0 < r) : a ∈ Metric.ball a r := Metric.mem_ball_self hr example (hr : 0 ≤ r) : a ∈ Metric.closedBall a r := Metric.mem_closedBall_self hr example (s : Set X) : IsOpen s ↔ ∀ x ∈ s, ∃ ε > 0, Metric.ball x ε ⊆ s := Metric.isOpen_iff example {s : Set X} : IsClosed s ↔ IsOpen (sᶜ) := isOpen_compl_iff.symm example {s : Set X} (hs : IsClosed s) {u : ℕ → X} (hu : Tendsto u atTop (𝓝 a)) (hus : ∀ n, u n ∈ s) : a ∈ s := hs.mem_of_tendsto hu (eventually_of_forall hus) example {s : Set X} : a ∈ closure s ↔ ∀ ε > 0, ∃ b ∈ s, a ∈ Metric.ball b ε := Metric.mem_closure_iff example {u : ℕ → X} (hu : Tendsto u atTop (𝓝 a)) {s : Set X} (hs : ∀ n, u n ∈ s) : a ∈ closure s := sorry example {u : ℕ → X} (hu : Tendsto u atTop (𝓝 a)) {s : Set X} (hs : ∀ n, u n ∈ s) : a ∈ closure s := by rw [Metric.tendsto_atTop] at hu rw [Metric.mem_closure_iff] intro ε ε_pos rcases hu ε ε_pos with ⟨N, hN⟩ refine' ⟨u N, hs _, _⟩ rw [dist_comm] exact hN N le_rfl example {x : X} {s : Set X} : s ∈ 𝓝 x ↔ ∃ ε > 0, Metric.ball x ε ⊆ s := Metric.nhds_basis_ball.mem_iff example {x : X} {s : Set X} : s ∈ 𝓝 x ↔ ∃ ε > 0, Metric.closedBall x ε ⊆ s := Metric.nhds_basis_closedBall.mem_iff example : IsCompact (Set.Icc 0 1 : Set ℝ) := isCompact_Icc example {s : Set X} (hs : IsCompact s) {u : ℕ → X} (hu : ∀ n, u n ∈ s) : ∃ a ∈ s, ∃ φ : ℕ → ℕ, StrictMono φ ∧ Tendsto (u ∘ φ) atTop (𝓝 a) := hs.tendsto_subseq hu example {s : Set X} (hs : IsCompact s) (hs' : s.Nonempty) {f : X → ℝ} (hfs : ContinuousOn f s) : ∃ x ∈ s, ∀ y ∈ s, f x ≤ f y := hs.exists_forall_le hs' hfs example {s : Set X} (hs : IsCompact s) (hs' : s.Nonempty) {f : X → ℝ} (hfs : ContinuousOn f s) : ∃ x ∈ s, ∀ y ∈ s, f y ≤ f x := hs.exists_forall_ge hs' hfs example {s : Set X} (hs : IsCompact s) : IsClosed s := hs.isClosed example {X : Type _} [MetricSpace X] [CompactSpace X] : IsCompact (univ : Set X) := isCompact_univ #check IsCompact.isClosed example {X : Type _} [MetricSpace X] {Y : Type _} [MetricSpace Y] {f : X → Y} : UniformContinuous f ↔ ∀ ε > 0, ∃ δ > 0, ∀ {a b : X}, dist a b < δ → dist (f a) (f b) < ε := Metric.uniformContinuous_iff example {X : Type _} [MetricSpace X] [CompactSpace X] {Y : Type _} [MetricSpace Y] {f : X → Y} (hf : Continuous f) : UniformContinuous f := sorry example {X : Type _} [MetricSpace X] [CompactSpace X] {Y : Type _} [MetricSpace Y] {f : X → Y} (hf : Continuous f) : UniformContinuous f := by rw [Metric.uniformContinuous_iff] intro ε ε_pos let φ : X × X → ℝ := fun p => dist (f p.1) (f p.2) have φ_cont : Continuous φ := hf.fst'.dist hf.snd' let K := { p : X × X | ε ≤ φ p } have K_closed : IsClosed K := isClosed_le continuous_const φ_cont have K_cpct : IsCompact K := K_closed.isCompact cases' eq_empty_or_nonempty K with hK hK · use 1, by norm_num intro x y _ have : (x, y) ∉ K := by simp [hK] simpa using this · rcases K_cpct.exists_forall_le hK continuous_dist.continuousOn with ⟨⟨x₀, x₁⟩, xx_in, H⟩ use dist x₀ x₁ constructor · change _ < _ rw [dist_pos] intro h have : ε ≤ 0 := by simpa [*] using xx_in linarith · intro x x' contrapose! intro hxx' exact H (x, x') hxx' example (u : ℕ → X) : CauchySeq u ↔ ∀ ε > 0, ∃ N : ℕ, ∀ m ≥ N, ∀ n ≥ N, dist (u m) (u n) < ε := Metric.cauchySeq_iff example (u : ℕ → X) : CauchySeq u ↔ ∀ ε > 0, ∃ N : ℕ, ∀ n ≥ N, dist (u n) (u N) < ε := Metric.cauchySeq_iff' example [CompleteSpace X] (u : ℕ → X) (hu : CauchySeq u) : ∃ x, Tendsto u atTop (𝓝 x) := cauchySeq_tendsto_of_complete hu open BigOperators open Finset theorem cauchySeq_of_le_geometric_two' {u : ℕ → X} (hu : ∀ n : ℕ, dist (u n) (u (n + 1)) ≤ (1 / 2) ^ n) : CauchySeq u := by rw [Metric.cauchySeq_iff'] intro ε ε_pos obtain ⟨N, hN⟩ : ∃ N : ℕ, 1 / 2 ^ N * 2 < ε := by sorry use N intro n hn obtain ⟨k, rfl : n = N + k⟩ := le_iff_exists_add.mp hn calc dist (u (N + k)) (u N) = dist (u (N + 0)) (u (N + k)) := sorry _ ≤ ∑ i in range k, dist (u (N + i)) (u (N + (i + 1))) := sorry _ ≤ ∑ i in range k, (1 / 2 : ℝ) ^ (N + i) := sorry _ = 1 / 2 ^ N * ∑ i in range k, (1 / 2) ^ i := sorry _ ≤ 1 / 2 ^ N * 2 := sorry _ < ε := sorry example {u : ℕ → X} (hu : ∀ n : ℕ, dist (u n) (u (n + 1)) ≤ (1 / 2) ^ n) : CauchySeq u := by rw [Metric.cauchySeq_iff'] intro ε ε_pos obtain ⟨N, hN⟩ : ∃ N : ℕ, 1 / 2 ^ N * 2 < ε := by have : Tendsto (fun N : ℕ => (1 / 2 ^ N * 2 : ℝ)) atTop (𝓝 0) := by rw [← MulZeroClass.zero_mul (2 : ℝ)] apply Tendsto.mul simp_rw [← one_div_pow (2 : ℝ)] apply tendsto_pow_atTop_nhds_0_of_lt_1 <;> linarith exact tendsto_const_nhds rcases(atTop_basis.tendsto_iff (nhds_basis_Ioo_pos (0 : ℝ))).mp this ε ε_pos with ⟨N, _, hN⟩ exact ⟨N, by simpa using (hN N left_mem_Ici).2⟩ use N intro n hn obtain ⟨k, rfl : n = N + k⟩ := le_iff_exists_add.mp hn calc dist (u (N + k)) (u N) = dist (u (N + 0)) (u (N + k)) := by rw [dist_comm, add_zero] _ ≤ ∑ i in range k, dist (u (N + i)) (u (N + (i + 1))) := (dist_le_range_sum_dist (fun i => u (N + i)) k) _ ≤ ∑ i in range k, (1 / 2 : ℝ) ^ (N + i) := (sum_le_sum fun i _ => hu <| N + i) _ = 1 / 2 ^ N * ∑ i in range k, (1 / 2 : ℝ) ^ i := by simp_rw [← one_div_pow, pow_add, ← mul_sum] _ ≤ 1 / 2 ^ N * 2 := (mul_le_mul_of_nonneg_left (sum_geometric_two_le _) (one_div_nonneg.mpr (pow_nonneg (zero_le_two : (0 : ℝ) ≤ 2) _))) _ < ε := hN open Metric example [CompleteSpace X] (f : ℕ → Set X) (ho : ∀ n, IsOpen (f n)) (hd : ∀ n, Dense (f n)) : Dense (⋂ n, f n) := by let B : ℕ → ℝ := fun n => (1 / 2) ^ n have Bpos : ∀ n, 0 < B n sorry /- Translate the density assumption into two functions `center` and `radius` associating to any n, x, δ, δpos a center and a positive radius such that `closedBall center radius` is included both in `f n` and in `closedBall x δ`. We can also require `radius ≤ (1/2)^(n+1)`, to ensure we get a Cauchy sequence later. -/ have : ∀ (n : ℕ) (x : X), ∀ δ > 0, ∃ y : X, ∃ r > 0, r ≤ B (n + 1) ∧ closedBall y r ⊆ closedBall x δ ∩ f n := by sorry choose! center radius Hpos HB Hball using this intro x rw [mem_closure_iff_nhds_basis nhds_basis_closedBall] intro ε εpos /- `ε` is positive. We have to find a point in the ball of radius `ε` around `x` belonging to all `f n`. For this, we construct inductively a sequence `F n = (c n, r n)` such that the closed ball `closedBall (c n) (r n)` is included in the previous ball and in `f n`, and such that `r n` is small enough to ensure that `c n` is a Cauchy sequence. Then `c n` converges to a limit which belongs to all the `f n`. -/ let F : ℕ → X × ℝ := fun n => Nat.recOn n (Prod.mk x (min ε (B 0))) fun n p => Prod.mk (center n p.1 p.2) (radius n p.1 p.2) let c : ℕ → X := fun n => (F n).1 let r : ℕ → ℝ := fun n => (F n).2 have rpos : ∀ n, 0 < r n := by sorry have rB : ∀ n, r n ≤ B n := by sorry have incl : ∀ n, closedBall (c (n + 1)) (r (n + 1)) ⊆ closedBall (c n) (r n) ∩ f n := by sorry have cdist : ∀ n, dist (c n) (c (n + 1)) ≤ B n := by sorry have : CauchySeq c := cauchySeq_of_le_geometric_two' cdist -- as the sequence `c n` is Cauchy in a complete space, it converges to a limit `y`. rcases cauchySeq_tendsto_of_complete this with ⟨y, ylim⟩ -- this point `y` will be the desired point. We will check that it belongs to all -- `f n` and to `ball x ε`. use y have I : ∀ n, ∀ m ≥ n, closedBall (c m) (r m) ⊆ closedBall (c n) (r n) := by sorry have yball : ∀ n, y ∈ closedBall (c n) (r n) := by sorry sorry example [CompleteSpace X] (f : ℕ → Set X) (ho : ∀ n, IsOpen (f n)) (hd : ∀ n, Dense (f n)) : Dense (⋂ n, f n) := by let B : ℕ → ℝ := fun n => (1 / 2) ^ n have Bpos : ∀ n, 0 < B n := fun n => pow_pos sorry n /- Translate the density assumption into two functions `center` and `radius` associating to any n, x, δ, δpos a center and a positive radius such that `closedBall center radius` is included both in `f n` and in `closedBall x δ`. We can also require `radius ≤ (1/2)^(n+1)`, to ensure we get a Cauchy sequence later. -/ have : ∀ (n : ℕ) (x : X), ∀ δ > 0, ∃ y : X, ∃ r > 0, r ≤ B (n + 1) ∧ closedBall y r ⊆ closedBall x δ ∩ f n := by intro n x δ δpos have : x ∈ closure (f n) := hd n x rcases Metric.mem_closure_iff.1 this (δ / 2) (half_pos δpos) with ⟨y, ys, xy⟩ rw [dist_comm] at xy obtain ⟨r, rpos, hr⟩ : ∃ r > 0, closedBall y r ⊆ f n := nhds_basis_closedBall.mem_iff.1 (isOpen_iff_mem_nhds.1 (ho n) y ys) refine' ⟨y, min (min (δ / 2) r) (B (n + 1)), _, _, fun z hz => ⟨_, _⟩⟩ show 0 < min (min (δ / 2) r) (B (n + 1)) exact lt_min (lt_min (half_pos δpos) rpos) (Bpos (n + 1)) show min (min (δ / 2) r) (B (n + 1)) ≤ B (n + 1) exact min_le_right _ _ show z ∈ closedBall x δ exact calc dist z x ≤ dist z y + dist y x := dist_triangle _ _ _ _ ≤ min (min (δ / 2) r) (B (n + 1)) + δ / 2 := (add_le_add hz xy.le) _ ≤ δ / 2 + δ / 2 := (add_le_add_right ((min_le_left _ _).trans (min_le_left _ _)) _) _ = δ := add_halves δ show z ∈ f n exact hr (calc dist z y ≤ min (min (δ / 2) r) (B (n + 1)) := hz _ ≤ r := (min_le_left _ _).trans (min_le_right _ _) ) choose! center radius Hpos HB Hball using this refine' fun x => (mem_closure_iff_nhds_basis nhds_basis_closedBall).2 fun ε εpos => _ /- `ε` is positive. We have to find a point in the ball of radius `ε` around `x` belonging to all `f n`. For this, we construct inductively a sequence `F n = (c n, r n)` such that the closed ball `closedBall (c n) (r n)` is included in the previous ball and in `f n`, and such that `r n` is small enough to ensure that `c n` is a Cauchy sequence. Then `c n` converges to a limit which belongs to all the `f n`. -/ let F : ℕ → X × ℝ := fun n => Nat.recOn n (Prod.mk x (min ε (B 0))) fun n p => Prod.mk (center n p.1 p.2) (radius n p.1 p.2) let c : ℕ → X := fun n => (F n).1 let r : ℕ → ℝ := fun n => (F n).2 have rpos : ∀ n, 0 < r n := by intro n induction' n with n hn exact lt_min εpos (Bpos 0) exact Hpos n (c n) (r n) hn have rB : ∀ n, r n ≤ B n := by intro n induction' n with n hn exact min_le_right _ _ exact HB n (c n) (r n) (rpos n) have incl : ∀ n, closedBall (c (n + 1)) (r (n + 1)) ⊆ closedBall (c n) (r n) ∩ f n := fun n => Hball n (c n) (r n) (rpos n) have cdist : ∀ n, dist (c n) (c (n + 1)) ≤ B n := by intro n rw [dist_comm] have A : c (n + 1) ∈ closedBall (c (n + 1)) (r (n + 1)) := mem_closedBall_self (rpos <| n + 1).le have I := calc closedBall (c (n + 1)) (r (n + 1)) ⊆ closedBall (c n) (r n) := (incl n).trans (inter_subset_left _ _) _ ⊆ closedBall (c n) (B n) := closedBall_subset_closedBall (rB n) exact I A have : CauchySeq c := cauchySeq_of_le_geometric_two' cdist -- as the sequence `c n` is Cauchy in a complete space, it converges to a limit `y`. rcases cauchySeq_tendsto_of_complete this with ⟨y, ylim⟩ -- this point `y` will be the desired point. We will check that it belongs to all -- `f n` and to `ball x ε`. use y have I : ∀ n, ∀ m ≥ n, closedBall (c m) (r m) ⊆ closedBall (c n) (r n) := by intro n refine' Nat.le_induction _ fun m hnm h => _ · exact Subset.rfl · exact (incl m).trans ((Set.inter_subset_left _ _).trans h) have yball : ∀ n, y ∈ closedBall (c n) (r n) := by intro n refine' isClosed_ball.mem_of_tendsto ylim _ refine' (Filter.eventually_ge_atTop n).mono fun m hm => _ exact I n m hm (mem_closedBall_self (rpos _).le) constructor · suffices ∀ n, y ∈ f n by rwa [Set.mem_iInter] intro n have : closedBall (c (n + 1)) (r (n + 1)) ⊆ f n := Subset.trans (incl n) (inter_subset_right _ _) exact this (yball (n + 1)) calc dist y x ≤ r 0 := yball 0 _ ≤ ε := min_le_left _ _
-
-
-
@@ -0,0 +1,207 @@import Mathlib.Topology.Instances.Real import Mathlib.Analysis.NormedSpace.BanachSteinhaus open Set Filter Topology section variable {X : Type _} [TopologicalSpace X] example : IsOpen (univ : Set X) := isOpen_univ example : IsOpen (∅ : Set X) := isOpen_empty example {ι : Type _} {s : ι → Set X} (hs : ∀ i, IsOpen <| s i) : IsOpen (⋃ i, s i) := isOpen_iUnion hs example {ι : Type _} [Fintype ι] {s : ι → Set X} (hs : ∀ i, IsOpen <| s i) : IsOpen (⋂ i, s i) := isOpen_iInter hs variable {Y : Type _} [TopologicalSpace Y] example {f : X → Y} : Continuous f ↔ ∀ s, IsOpen s → IsOpen (f ⁻¹' s) := continuous_def example {f : X → Y} {x : X} : ContinuousAt f x ↔ map f (𝓝 x) ≤ 𝓝 (f x) := Iff.rfl example {f : X → Y} {x : X} : ContinuousAt f x ↔ ∀ U ∈ 𝓝 (f x), ∀ᶠ x in 𝓝 x, f x ∈ U := Iff.rfl example {x : X} {s : Set X} : s ∈ 𝓝 x ↔ ∃ t, t ⊆ s ∧ IsOpen t ∧ x ∈ t := mem_nhds_iff example (x : X) : pure x ≤ 𝓝 x := pure_le_nhds x example (x : X) (P : X → Prop) (h : ∀ᶠ y in 𝓝 x, P y) : P x := pure_le_nhds x h example {P : X → Prop} {x : X} (h : ∀ᶠ y in 𝓝 x, P y) : ∀ᶠ y in 𝓝 x, ∀ᶠ z in 𝓝 y, P z := eventually_eventually_nhds.mpr h #check TopologicalSpace.mkOfNhds #check TopologicalSpace.nhds_mkOfNhds example {α : Type _} (n : α → Filter α) (H₀ : ∀ a, pure a ≤ n a) (H : ∀ a : α, ∀ p : α → Prop, (∀ᶠ x in n a, p x) → ∀ᶠ y in n a, ∀ᶠ x in n y, p x) : ∀ a, ∀ s ∈ n a, ∃ t ∈ n a, t ⊆ s ∧ ∀ a' ∈ t, s ∈ n a' := sorry example {α : Type _} (n : α → Filter α) (H₀ : ∀ a, pure a ≤ n a) (H : ∀ a : α, ∀ p : α → Prop, (∀ᶠ x in n a, p x) → ∀ᶠ y in n a, ∀ᶠ x in n y, p x) : ∀ a, ∀ s ∈ n a, ∃ t ∈ n a, t ⊆ s ∧ ∀ a' ∈ t, s ∈ n a' := by intro a s s_in refine' ⟨{ y | s ∈ n y }, H a (fun x => x ∈ s) s_in, _, by tauto⟩ rintro y (hy : s ∈ n y) exact H₀ y hy end -- BOTH. variable {X Y : Type _} example (f : X → Y) : TopologicalSpace X → TopologicalSpace Y := TopologicalSpace.coinduced f example (f : X → Y) : TopologicalSpace Y → TopologicalSpace X := TopologicalSpace.induced f example (f : X → Y) (T_X : TopologicalSpace X) (T_Y : TopologicalSpace Y) : TopologicalSpace.coinduced f T_X ≤ T_Y ↔ T_X ≤ TopologicalSpace.induced f T_Y := coinduced_le_iff_le_induced #check coinduced_compose #check induced_compose example {T T' : TopologicalSpace X} : T ≤ T' ↔ ∀ s, T'.IsOpen s → T.IsOpen s := Iff.rfl example (T_X : TopologicalSpace X) (T_Y : TopologicalSpace Y) (f : X → Y) : Continuous f ↔ TopologicalSpace.coinduced f T_X ≤ T_Y := continuous_iff_coinduced_le example {Z : Type _} (f : X → Y) (T_X : TopologicalSpace X) (T_Z : TopologicalSpace Z) (g : Y → Z) : @Continuous Y Z (TopologicalSpace.coinduced f T_X) T_Z g ↔ @Continuous X Z T_X T_Z (g ∘ f) := by rw [continuous_iff_coinduced_le, coinduced_compose, continuous_iff_coinduced_le] example (ι : Type _) (X : ι → Type _) (T_X : ∀ i, TopologicalSpace <| X i) : (Pi.topologicalSpace : TopologicalSpace (∀ i, X i)) = ⨅ i, TopologicalSpace.induced (fun x => x i) (T_X i) := rfl example [TopologicalSpace X] [T2Space X] {u : ℕ → X} {a b : X} (ha : Tendsto u atTop (𝓝 a)) (hb : Tendsto u atTop (𝓝 b)) : a = b := tendsto_nhds_unique ha hb example [TopologicalSpace X] [RegularSpace X] (a : X) : (𝓝 a).HasBasis (fun s : Set X => s ∈ 𝓝 a ∧ IsClosed s) id := closed_nhds_basis a example [TopologicalSpace X] {x : X} : (𝓝 x).HasBasis (fun t : Set X => t ∈ 𝓝 x ∧ IsOpen t) id := nhds_basis_opens' x theorem aux {X Y A : Type _} [TopologicalSpace X] {c : A → X} {f : A → Y} {x : X} {F : Filter Y} (h : Tendsto f (comap c (𝓝 x)) F) {V' : Set Y} (V'_in : V' ∈ F) : ∃ V ∈ 𝓝 x, IsOpen V ∧ c ⁻¹' V ⊆ f ⁻¹' V' := sorry example {X Y A : Type _} [TopologicalSpace X] {c : A → X} {f : A → Y} {x : X} {F : Filter Y} (h : Tendsto f (comap c (𝓝 x)) F) {V' : Set Y} (V'_in : V' ∈ F) : ∃ V ∈ 𝓝 x, IsOpen V ∧ c ⁻¹' V ⊆ f ⁻¹' V' := by simpa [and_assoc] using ((nhds_basis_opens' x).comap c).tendsto_left_iff.mp h V' V'_in example [TopologicalSpace X] [TopologicalSpace Y] [RegularSpace Y] {A : Set X} (hA : ∀ x, x ∈ closure A) {f : A → Y} (f_cont : Continuous f) (hf : ∀ x : X, ∃ c : Y, Tendsto f (comap (↑) <| 𝓝 x) <| 𝓝 c) : ∃ φ : X → Y, Continuous φ ∧ ∀ a : A, φ a = f a := sorry #check @HasBasis.tendsto_right_iff example [TopologicalSpace X] [TopologicalSpace Y] [T3Space Y] {A : Set X} (hA : ∀ x, x ∈ closure A) {f : A → Y} (f_cont : Continuous f) (hf : ∀ x : X, ∃ c : Y, Tendsto f (comap (↑) <| 𝓝 x) <| 𝓝 c) : ∃ φ : X → Y, Continuous φ ∧ ∀ a : A, φ a = f a := by choose φ hφ using hf use φ constructor · rw [continuous_iff_continuousAt] intro x suffices ∀ V' ∈ 𝓝 (φ x), IsClosed V' → φ ⁻¹' V' ∈ 𝓝 x by simpa [ContinuousAt, (closed_nhds_basis (φ x)).tendsto_right_iff] intro V' V'_in V'_closed obtain ⟨V, V_in, V_op, hV⟩ : ∃ V ∈ 𝓝 x, IsOpen V ∧ (↑) ⁻¹' V ⊆ f ⁻¹' V' := aux (hφ x) V'_in suffices : ∀ y ∈ V, φ y ∈ V' exact mem_of_superset V_in this intro y y_in have hVx : V ∈ 𝓝 y := V_op.mem_nhds y_in haveI : (comap ((↑) : A → X) (𝓝 y)).NeBot := by simpa [mem_closure_iff_comap_neBot] using hA y apply V'_closed.mem_of_tendsto (hφ y) exact mem_of_superset (preimage_mem_comap hVx) hV · intro a have lim : Tendsto f (𝓝 a) (𝓝 <| φ a) := by simpa [nhds_induced] using hφ a exact tendsto_nhds_unique lim f_cont.continuousAt example [TopologicalSpace X] [TopologicalSpace.FirstCountableTopology X] {s : Set X} {a : X} : a ∈ closure s ↔ ∃ u : ℕ → X, (∀ n, u n ∈ s) ∧ Tendsto u atTop (𝓝 a) := mem_closure_iff_seq_limit variable [TopologicalSpace X] example {F : Filter X} {x : X} : ClusterPt x F ↔ NeBot (𝓝 x ⊓ F) := Iff.rfl example {s : Set X} : IsCompact s ↔ ∀ (F : Filter X) [NeBot F], F ≤ 𝓟 s → ∃ a ∈ s, ClusterPt a F := Iff.rfl example [TopologicalSpace.FirstCountableTopology X] {s : Set X} {u : ℕ → X} (hs : IsCompact s) (hu : ∀ n, u n ∈ s) : ∃ a ∈ s, ∃ φ : ℕ → ℕ, StrictMono φ ∧ Tendsto (u ∘ φ) atTop (𝓝 a) := hs.tendsto_subseq hu variable [TopologicalSpace Y] example {x : X} {F : Filter X} {G : Filter Y} (H : ClusterPt x F) {f : X → Y} (hfx : ContinuousAt f x) (hf : Tendsto f F G) : ClusterPt (f x) G := ClusterPt.map H hfx hf example [TopologicalSpace Y] {f : X → Y} (hf : Continuous f) {s : Set X} (hs : IsCompact s) : IsCompact (f '' s) := by intro F F_ne F_le have map_eq : map f (𝓟 s ⊓ comap f F) = 𝓟 (f '' s) ⊓ F := by sorry have Hne : (𝓟 s ⊓ comap f F).NeBot := by sorry have Hle : 𝓟 s ⊓ comap f F ≤ 𝓟 s := inf_le_left sorry example [TopologicalSpace Y] {f : X → Y} (hf : Continuous f) {s : Set X} (hs : IsCompact s) : IsCompact (f '' s) := by intro F F_ne F_le have map_eq : map f (𝓟 s ⊓ comap f F) = 𝓟 (f '' s) ⊓ F := by rw [Filter.push_pull, map_principal] have Hne : (𝓟 s ⊓ comap f F).NeBot := by apply NeBot.of_map rwa [map_eq, inf_of_le_right F_le] have Hle : 𝓟 s ⊓ comap f F ≤ 𝓟 s := inf_le_left rcases hs Hle with ⟨x, x_in, hx⟩ refine' ⟨f x, mem_image_of_mem f x_in, _⟩ apply hx.map hf.continuousAt rw [Tendsto, map_eq] exact inf_le_right example {ι : Type _} {s : Set X} (hs : IsCompact s) (U : ι → Set X) (hUo : ∀ i, IsOpen (U i)) (hsU : s ⊆ ⋃ i, U i) : ∃ t : Finset ι, s ⊆ ⋃ i ∈ t, U i := hs.elim_finite_subcover U hUo hsU example [CompactSpace X] : IsCompact (univ : Set X) := isCompact_univ
-
-
-
@@ -0,0 +1,105 @@import Mathlib.Topology.Instances.Real open Set Filter Topology def principal {α : Type _} (s : Set α) : Filter α where sets := { t | s ⊆ t } univ_sets := sorry sets_of_superset := sorry inter_sets := sorry example : Filter ℕ := { sets := { s | ∃ a, ∀ b, a ≤ b → b ∈ s } univ_sets := sorry sets_of_superset := sorry inter_sets := sorry } def Tendsto₁ {X Y : Type _} (f : X → Y) (F : Filter X) (G : Filter Y) := ∀ V ∈ G, f ⁻¹' V ∈ F def Tendsto₂ {X Y : Type _} (f : X → Y) (F : Filter X) (G : Filter Y) := map f F ≤ G example {X Y : Type _} (f : X → Y) (F : Filter X) (G : Filter Y) : Tendsto₂ f F G ↔ Tendsto₁ f F G := Iff.rfl #check (@Filter.map_mono : ∀ {α β} {m : α → β}, Monotone (map m)) #check (@Filter.map_map : ∀ {α β γ} {f : Filter α} {m : α → β} {m' : β → γ}, map m' (map m f) = map (m' ∘ m) f) example {X Y Z : Type _} {F : Filter X} {G : Filter Y} {H : Filter Z} {f : X → Y} {g : Y → Z} (hf : Tendsto₁ f F G) (hg : Tendsto₁ g G H) : Tendsto₁ (g ∘ f) F H := sorry variable (f : ℝ → ℝ) (x₀ y₀ : ℝ) #check comap ((↑) : ℚ → ℝ) (𝓝 x₀) #check Tendsto (f ∘ (↑)) (comap ((↑) : ℚ → ℝ) (𝓝 x₀)) (𝓝 y₀) section variable {α β γ : Type _} (F : Filter α) {m : γ → β} {n : β → α} #check (comap_comap : comap m (comap n F) = comap (n ∘ m) F) end example : 𝓝 (x₀, y₀) = 𝓝 x₀ ×ˢ 𝓝 y₀ := nhds_prod_eq #check le_inf_iff example (f : ℕ → ℝ × ℝ) (x₀ y₀ : ℝ) : Tendsto f atTop (𝓝 (x₀, y₀)) ↔ Tendsto (Prod.fst ∘ f) atTop (𝓝 x₀) ∧ Tendsto (Prod.snd ∘ f) atTop (𝓝 y₀) := sorry example (x₀ : ℝ) : HasBasis (𝓝 x₀) (fun ε : ℝ => 0 < ε) fun ε => Ioo (x₀ - ε) (x₀ + ε) := nhds_basis_Ioo_pos x₀ example (u : ℕ → ℝ) (x₀ : ℝ) : Tendsto u atTop (𝓝 x₀) ↔ ∀ ε > 0, ∃ N, ∀ n ≥ N, u n ∈ Ioo (x₀ - ε) (x₀ + ε) := by have : atTop.HasBasis (fun _ : ℕ => True) Ici := atTop_basis rw [this.tendsto_iff (nhds_basis_Ioo_pos x₀)] simp example (P Q : ℕ → Prop) (hP : ∀ᶠ n in atTop, P n) (hQ : ∀ᶠ n in atTop, Q n) : ∀ᶠ n in atTop, P n ∧ Q n := hP.and hQ example (u v : ℕ → ℝ) (h : ∀ᶠ n in atTop, u n = v n) (x₀ : ℝ) : Tendsto u atTop (𝓝 x₀) ↔ Tendsto v atTop (𝓝 x₀) := tendsto_congr' h example (u v : ℕ → ℝ) (h : u =ᶠ[atTop] v) (x₀ : ℝ) : Tendsto u atTop (𝓝 x₀) ↔ Tendsto v atTop (𝓝 x₀) := tendsto_congr' h #check @eventually_of_forall #check @Eventually.mono #check @Eventually.and example (P Q R : ℕ → Prop) (hP : ∀ᶠ n in atTop, P n) (hQ : ∀ᶠ n in atTop, Q n) (hR : ∀ᶠ n in atTop, P n ∧ Q n → R n) : ∀ᶠ n in atTop, R n := by apply (hP.and (hQ.and hR)).mono rintro n ⟨h, h', h''⟩ exact h'' ⟨h, h'⟩ example (P Q R : ℕ → Prop) (hP : ∀ᶠ n in atTop, P n) (hQ : ∀ᶠ n in atTop, Q n) (hR : ∀ᶠ n in atTop, P n ∧ Q n → R n) : ∀ᶠ n in atTop, R n := by filter_upwards [hP, hQ, hR] intro n h h' h'' exact h'' ⟨h, h'⟩ #check mem_closure_iff_clusterPt #check le_principal_iff #check neBot_of_le example (u : ℕ → ℝ) (M : Set ℝ) (x : ℝ) (hux : Tendsto u atTop (𝓝 x)) (huM : ∀ᶠ n in atTop, u n ∈ M) : x ∈ closure M := sorry
-
-
-
@@ -0,0 +1,206 @@import Mathlib.Topology.Instances.Real import Mathlib.Analysis.NormedSpace.BanachSteinhaus open Set Filter open Topology Filter variable {X : Type _} [MetricSpace X] (a b c : X) #check (dist a b : ℝ) #check (dist_nonneg : 0 ≤ dist a b) #check (dist_eq_zero : dist a b = 0 ↔ a = b) #check (dist_comm a b : dist a b = dist b a) #check (dist_triangle a b c : dist a c ≤ dist a b + dist b c) -- Note the next three lines are not quoted, their purpose is to make sure those things don't get renamed while we're looking elsewhere. #check EMetricSpace #check PseudoMetricSpace #check PseudoEMetricSpace example {u : ℕ → X} {a : X} : Tendsto u atTop (𝓝 a) ↔ ∀ ε > 0, ∃ N, ∀ n ≥ N, dist (u n) a < ε := Metric.tendsto_atTop example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} : Continuous f ↔ ∀ x : X, ∀ ε > 0, ∃ δ > 0, ∀ x', dist x' x < δ → dist (f x') (f x) < ε := Metric.continuous_iff example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := by continuity example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := continuous_dist.comp ((hf.comp continuous_fst).prod_mk (hf.comp continuous_snd)) example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := by apply Continuous.dist exact hf.comp continuous_fst exact hf.comp continuous_snd example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := (hf.comp continuous_fst).dist (hf.comp continuous_snd) example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := hf.fst'.dist hf.snd' example {f : ℝ → X} (hf : Continuous f) : Continuous fun x : ℝ => f (x ^ 2 + x) := sorry example {X Y : Type _} [MetricSpace X] [MetricSpace Y] (f : X → Y) (a : X) : ContinuousAt f a ↔ ∀ ε > 0, ∃ δ > 0, ∀ {x}, dist x a < δ → dist (f x) (f a) < ε := Metric.continuousAt_iff variable (r : ℝ) example : Metric.ball a r = { b | dist b a < r } := rfl example : Metric.closedBall a r = { b | dist b a ≤ r } := rfl example (hr : 0 < r) : a ∈ Metric.ball a r := Metric.mem_ball_self hr example (hr : 0 ≤ r) : a ∈ Metric.closedBall a r := Metric.mem_closedBall_self hr example (s : Set X) : IsOpen s ↔ ∀ x ∈ s, ∃ ε > 0, Metric.ball x ε ⊆ s := Metric.isOpen_iff example {s : Set X} : IsClosed s ↔ IsOpen (sᶜ) := isOpen_compl_iff.symm example {s : Set X} (hs : IsClosed s) {u : ℕ → X} (hu : Tendsto u atTop (𝓝 a)) (hus : ∀ n, u n ∈ s) : a ∈ s := hs.mem_of_tendsto hu (eventually_of_forall hus) example {s : Set X} : a ∈ closure s ↔ ∀ ε > 0, ∃ b ∈ s, a ∈ Metric.ball b ε := Metric.mem_closure_iff example {u : ℕ → X} (hu : Tendsto u atTop (𝓝 a)) {s : Set X} (hs : ∀ n, u n ∈ s) : a ∈ closure s := sorry example {x : X} {s : Set X} : s ∈ 𝓝 x ↔ ∃ ε > 0, Metric.ball x ε ⊆ s := Metric.nhds_basis_ball.mem_iff example {x : X} {s : Set X} : s ∈ 𝓝 x ↔ ∃ ε > 0, Metric.closedBall x ε ⊆ s := Metric.nhds_basis_closedBall.mem_iff example : IsCompact (Set.Icc 0 1 : Set ℝ) := isCompact_Icc example {s : Set X} (hs : IsCompact s) {u : ℕ → X} (hu : ∀ n, u n ∈ s) : ∃ a ∈ s, ∃ φ : ℕ → ℕ, StrictMono φ ∧ Tendsto (u ∘ φ) atTop (𝓝 a) := hs.tendsto_subseq hu example {s : Set X} (hs : IsCompact s) (hs' : s.Nonempty) {f : X → ℝ} (hfs : ContinuousOn f s) : ∃ x ∈ s, ∀ y ∈ s, f x ≤ f y := hs.exists_forall_le hs' hfs example {s : Set X} (hs : IsCompact s) (hs' : s.Nonempty) {f : X → ℝ} (hfs : ContinuousOn f s) : ∃ x ∈ s, ∀ y ∈ s, f y ≤ f x := hs.exists_forall_ge hs' hfs example {s : Set X} (hs : IsCompact s) : IsClosed s := hs.isClosed example {X : Type _} [MetricSpace X] [CompactSpace X] : IsCompact (univ : Set X) := isCompact_univ #check IsCompact.isClosed example {X : Type _} [MetricSpace X] {Y : Type _} [MetricSpace Y] {f : X → Y} : UniformContinuous f ↔ ∀ ε > 0, ∃ δ > 0, ∀ {a b : X}, dist a b < δ → dist (f a) (f b) < ε := Metric.uniformContinuous_iff example {X : Type _} [MetricSpace X] [CompactSpace X] {Y : Type _} [MetricSpace Y] {f : X → Y} (hf : Continuous f) : UniformContinuous f := sorry example (u : ℕ → X) : CauchySeq u ↔ ∀ ε > 0, ∃ N : ℕ, ∀ m ≥ N, ∀ n ≥ N, dist (u m) (u n) < ε := Metric.cauchySeq_iff example (u : ℕ → X) : CauchySeq u ↔ ∀ ε > 0, ∃ N : ℕ, ∀ n ≥ N, dist (u n) (u N) < ε := Metric.cauchySeq_iff' example [CompleteSpace X] (u : ℕ → X) (hu : CauchySeq u) : ∃ x, Tendsto u atTop (𝓝 x) := cauchySeq_tendsto_of_complete hu open BigOperators open Finset theorem cauchySeq_of_le_geometric_two' {u : ℕ → X} (hu : ∀ n : ℕ, dist (u n) (u (n + 1)) ≤ (1 / 2) ^ n) : CauchySeq u := by rw [Metric.cauchySeq_iff'] intro ε ε_pos obtain ⟨N, hN⟩ : ∃ N : ℕ, 1 / 2 ^ N * 2 < ε := by sorry use N intro n hn obtain ⟨k, rfl : n = N + k⟩ := le_iff_exists_add.mp hn calc dist (u (N + k)) (u N) = dist (u (N + 0)) (u (N + k)) := sorry _ ≤ ∑ i in range k, dist (u (N + i)) (u (N + (i + 1))) := sorry _ ≤ ∑ i in range k, (1 / 2 : ℝ) ^ (N + i) := sorry _ = 1 / 2 ^ N * ∑ i in range k, (1 / 2) ^ i := sorry _ ≤ 1 / 2 ^ N * 2 := sorry _ < ε := sorry open Metric example [CompleteSpace X] (f : ℕ → Set X) (ho : ∀ n, IsOpen (f n)) (hd : ∀ n, Dense (f n)) : Dense (⋂ n, f n) := by let B : ℕ → ℝ := fun n => (1 / 2) ^ n have Bpos : ∀ n, 0 < B n sorry /- Translate the density assumption into two functions `center` and `radius` associating to any n, x, δ, δpos a center and a positive radius such that `closedBall center radius` is included both in `f n` and in `closedBall x δ`. We can also require `radius ≤ (1/2)^(n+1)`, to ensure we get a Cauchy sequence later. -/ have : ∀ (n : ℕ) (x : X), ∀ δ > 0, ∃ y : X, ∃ r > 0, r ≤ B (n + 1) ∧ closedBall y r ⊆ closedBall x δ ∩ f n := by sorry choose! center radius Hpos HB Hball using this intro x rw [mem_closure_iff_nhds_basis nhds_basis_closedBall] intro ε εpos /- `ε` is positive. We have to find a point in the ball of radius `ε` around `x` belonging to all `f n`. For this, we construct inductively a sequence `F n = (c n, r n)` such that the closed ball `closedBall (c n) (r n)` is included in the previous ball and in `f n`, and such that `r n` is small enough to ensure that `c n` is a Cauchy sequence. Then `c n` converges to a limit which belongs to all the `f n`. -/ let F : ℕ → X × ℝ := fun n => Nat.recOn n (Prod.mk x (min ε (B 0))) fun n p => Prod.mk (center n p.1 p.2) (radius n p.1 p.2) let c : ℕ → X := fun n => (F n).1 let r : ℕ → ℝ := fun n => (F n).2 have rpos : ∀ n, 0 < r n := by sorry have rB : ∀ n, r n ≤ B n := by sorry have incl : ∀ n, closedBall (c (n + 1)) (r (n + 1)) ⊆ closedBall (c n) (r n) ∩ f n := by sorry have cdist : ∀ n, dist (c n) (c (n + 1)) ≤ B n := by sorry have : CauchySeq c := cauchySeq_of_le_geometric_two' cdist -- as the sequence `c n` is Cauchy in a complete space, it converges to a limit `y`. rcases cauchySeq_tendsto_of_complete this with ⟨y, ylim⟩ -- this point `y` will be the desired point. We will check that it belongs to all -- `f n` and to `ball x ε`. use y have I : ∀ n, ∀ m ≥ n, closedBall (c m) (r m) ⊆ closedBall (c n) (r n) := by sorry have yball : ∀ n, y ∈ closedBall (c n) (r n) := by sorry sorry
-
-
-
@@ -0,0 +1,155 @@import Mathlib.Topology.Instances.Real import Mathlib.Analysis.NormedSpace.BanachSteinhaus open Set Filter Topology section variable {X : Type _} [TopologicalSpace X] example : IsOpen (univ : Set X) := isOpen_univ example : IsOpen (∅ : Set X) := isOpen_empty example {ι : Type _} {s : ι → Set X} (hs : ∀ i, IsOpen <| s i) : IsOpen (⋃ i, s i) := isOpen_iUnion hs example {ι : Type _} [Fintype ι] {s : ι → Set X} (hs : ∀ i, IsOpen <| s i) : IsOpen (⋂ i, s i) := isOpen_iInter hs variable {Y : Type _} [TopologicalSpace Y] example {f : X → Y} : Continuous f ↔ ∀ s, IsOpen s → IsOpen (f ⁻¹' s) := continuous_def example {f : X → Y} {x : X} : ContinuousAt f x ↔ map f (𝓝 x) ≤ 𝓝 (f x) := Iff.rfl example {f : X → Y} {x : X} : ContinuousAt f x ↔ ∀ U ∈ 𝓝 (f x), ∀ᶠ x in 𝓝 x, f x ∈ U := Iff.rfl example {x : X} {s : Set X} : s ∈ 𝓝 x ↔ ∃ t, t ⊆ s ∧ IsOpen t ∧ x ∈ t := mem_nhds_iff example (x : X) : pure x ≤ 𝓝 x := pure_le_nhds x example (x : X) (P : X → Prop) (h : ∀ᶠ y in 𝓝 x, P y) : P x := pure_le_nhds x h example {P : X → Prop} {x : X} (h : ∀ᶠ y in 𝓝 x, P y) : ∀ᶠ y in 𝓝 x, ∀ᶠ z in 𝓝 y, P z := eventually_eventually_nhds.mpr h #check TopologicalSpace.mkOfNhds #check TopologicalSpace.nhds_mkOfNhds example {α : Type _} (n : α → Filter α) (H₀ : ∀ a, pure a ≤ n a) (H : ∀ a : α, ∀ p : α → Prop, (∀ᶠ x in n a, p x) → ∀ᶠ y in n a, ∀ᶠ x in n y, p x) : ∀ a, ∀ s ∈ n a, ∃ t ∈ n a, t ⊆ s ∧ ∀ a' ∈ t, s ∈ n a' := sorry end -- BOTH. variable {X Y : Type _} example (f : X → Y) : TopologicalSpace X → TopologicalSpace Y := TopologicalSpace.coinduced f example (f : X → Y) : TopologicalSpace Y → TopologicalSpace X := TopologicalSpace.induced f example (f : X → Y) (T_X : TopologicalSpace X) (T_Y : TopologicalSpace Y) : TopologicalSpace.coinduced f T_X ≤ T_Y ↔ T_X ≤ TopologicalSpace.induced f T_Y := coinduced_le_iff_le_induced #check coinduced_compose #check induced_compose example {T T' : TopologicalSpace X} : T ≤ T' ↔ ∀ s, T'.IsOpen s → T.IsOpen s := Iff.rfl example (T_X : TopologicalSpace X) (T_Y : TopologicalSpace Y) (f : X → Y) : Continuous f ↔ TopologicalSpace.coinduced f T_X ≤ T_Y := continuous_iff_coinduced_le example {Z : Type _} (f : X → Y) (T_X : TopologicalSpace X) (T_Z : TopologicalSpace Z) (g : Y → Z) : @Continuous Y Z (TopologicalSpace.coinduced f T_X) T_Z g ↔ @Continuous X Z T_X T_Z (g ∘ f) := by rw [continuous_iff_coinduced_le, coinduced_compose, continuous_iff_coinduced_le] example (ι : Type _) (X : ι → Type _) (T_X : ∀ i, TopologicalSpace <| X i) : (Pi.topologicalSpace : TopologicalSpace (∀ i, X i)) = ⨅ i, TopologicalSpace.induced (fun x => x i) (T_X i) := rfl example [TopologicalSpace X] [T2Space X] {u : ℕ → X} {a b : X} (ha : Tendsto u atTop (𝓝 a)) (hb : Tendsto u atTop (𝓝 b)) : a = b := tendsto_nhds_unique ha hb example [TopologicalSpace X] [RegularSpace X] (a : X) : (𝓝 a).HasBasis (fun s : Set X => s ∈ 𝓝 a ∧ IsClosed s) id := closed_nhds_basis a example [TopologicalSpace X] {x : X} : (𝓝 x).HasBasis (fun t : Set X => t ∈ 𝓝 x ∧ IsOpen t) id := nhds_basis_opens' x theorem aux {X Y A : Type _} [TopologicalSpace X] {c : A → X} {f : A → Y} {x : X} {F : Filter Y} (h : Tendsto f (comap c (𝓝 x)) F) {V' : Set Y} (V'_in : V' ∈ F) : ∃ V ∈ 𝓝 x, IsOpen V ∧ c ⁻¹' V ⊆ f ⁻¹' V' := sorry example [TopologicalSpace X] [TopologicalSpace Y] [RegularSpace Y] {A : Set X} (hA : ∀ x, x ∈ closure A) {f : A → Y} (f_cont : Continuous f) (hf : ∀ x : X, ∃ c : Y, Tendsto f (comap (↑) <| 𝓝 x) <| 𝓝 c) : ∃ φ : X → Y, Continuous φ ∧ ∀ a : A, φ a = f a := sorry #check @HasBasis.tendsto_right_iff example [TopologicalSpace X] [TopologicalSpace.FirstCountableTopology X] {s : Set X} {a : X} : a ∈ closure s ↔ ∃ u : ℕ → X, (∀ n, u n ∈ s) ∧ Tendsto u atTop (𝓝 a) := mem_closure_iff_seq_limit variable [TopologicalSpace X] example {F : Filter X} {x : X} : ClusterPt x F ↔ NeBot (𝓝 x ⊓ F) := Iff.rfl example {s : Set X} : IsCompact s ↔ ∀ (F : Filter X) [NeBot F], F ≤ 𝓟 s → ∃ a ∈ s, ClusterPt a F := Iff.rfl example [TopologicalSpace.FirstCountableTopology X] {s : Set X} {u : ℕ → X} (hs : IsCompact s) (hu : ∀ n, u n ∈ s) : ∃ a ∈ s, ∃ φ : ℕ → ℕ, StrictMono φ ∧ Tendsto (u ∘ φ) atTop (𝓝 a) := hs.tendsto_subseq hu variable [TopologicalSpace Y] example {x : X} {F : Filter X} {G : Filter Y} (H : ClusterPt x F) {f : X → Y} (hfx : ContinuousAt f x) (hf : Tendsto f F G) : ClusterPt (f x) G := ClusterPt.map H hfx hf example [TopologicalSpace Y] {f : X → Y} (hf : Continuous f) {s : Set X} (hs : IsCompact s) : IsCompact (f '' s) := by intro F F_ne F_le have map_eq : map f (𝓟 s ⊓ comap f F) = 𝓟 (f '' s) ⊓ F := by sorry have Hne : (𝓟 s ⊓ comap f F).NeBot := by sorry have Hle : 𝓟 s ⊓ comap f F ≤ 𝓟 s := inf_le_left sorry example {ι : Type _} {s : Set X} (hs : IsCompact s) (U : ι → Set X) (hUo : ∀ i, IsOpen (U i)) (hsU : s ⊆ ⋃ i, U i) : ∃ t : Finset ι, s ⊆ ⋃ i ∈ t, U i := hs.elim_finite_subcover U hUo hsU example [CompactSpace X] : IsCompact (univ : Set X) := isCompact_univ
-
-
-
@@ -0,0 +1,71 @@import Mathlib.Topology.Instances.Real open Set Filter Topology -- In the next example we could use `tauto` in each proof instead of knowing the lemmas example {α : Type _} (s : Set α) : Filter α := { sets := { t | s ⊆ t } univ_sets := subset_univ s sets_of_superset := fun hU hUV => Subset.trans hU hUV inter_sets := fun hU hV => subset_inter hU hV } example : Filter ℕ := { sets := { s | ∃ a, ∀ b, a ≤ b → b ∈ s } univ_sets := by use 42 simp sets_of_superset := by rintro U V ⟨N, hN⟩ hUV use N tauto inter_sets := by rintro U V ⟨N, hN⟩ ⟨N', hN'⟩ use max N N' intro b hb rw [max_le_iff] at hb constructor <;> tauto } def Tendsto₁ {X Y : Type _} (f : X → Y) (F : Filter X) (G : Filter Y) := ∀ V ∈ G, f ⁻¹' V ∈ F example {X Y Z : Type _} {F : Filter X} {G : Filter Y} {H : Filter Z} {f : X → Y} {g : Y → Z} (hf : Tendsto₁ f F G) (hg : Tendsto₁ g G H) : Tendsto₁ (g ∘ f) F H := calc map (g ∘ f) F = map g (map f F) := by rw [map_map] _ ≤ map g G := (map_mono hf) _ ≤ H := hg example {X Y Z : Type _} {F : Filter X} {G : Filter Y} {H : Filter Z} {f : X → Y} {g : Y → Z} (hf : Tendsto₁ f F G) (hg : Tendsto₁ g G H) : Tendsto₁ (g ∘ f) F H := by intro V hV rw [preimage_comp] apply hf apply hg exact hV example (f : ℕ → ℝ × ℝ) (x₀ y₀ : ℝ) : Tendsto f atTop (𝓝 (x₀, y₀)) ↔ Tendsto (Prod.fst ∘ f) atTop (𝓝 x₀) ∧ Tendsto (Prod.snd ∘ f) atTop (𝓝 y₀) := calc Tendsto f atTop (𝓝 (x₀, y₀)) ↔ map f atTop ≤ 𝓝 (x₀, y₀) := Iff.rfl _ ↔ map f atTop ≤ 𝓝 x₀ ×ˢ 𝓝 y₀ := by rw [nhds_prod_eq] _ ↔ map f atTop ≤ comap Prod.fst (𝓝 x₀) ⊓ comap Prod.snd (𝓝 y₀) := Iff.rfl _ ↔ map f atTop ≤ comap Prod.fst (𝓝 x₀) ∧ map f atTop ≤ comap Prod.snd (𝓝 y₀) := le_inf_iff _ ↔ map Prod.fst (map f atTop) ≤ 𝓝 x₀ ∧ map Prod.snd (map f atTop) ≤ 𝓝 y₀ := by rw [← map_le_iff_le_comap, ← map_le_iff_le_comap] _ ↔ map (Prod.fst ∘ f) atTop ≤ 𝓝 x₀ ∧ map (Prod.snd ∘ f) atTop ≤ 𝓝 y₀ := by rw [map_map, map_map] -- an alternative solution example (f : ℕ → ℝ × ℝ) (x₀ y₀ : ℝ) : Tendsto f atTop (𝓝 (x₀, y₀)) ↔ Tendsto (Prod.fst ∘ f) atTop (𝓝 x₀) ∧ Tendsto (Prod.snd ∘ f) atTop (𝓝 y₀) := by rw [nhds_prod_eq] unfold Tendsto SProd.sprod Filter.instSProd Filter.prod erw [le_inf_iff, ← map_le_iff_le_comap, map_map, ← map_le_iff_le_comap, map_map] example (u : ℕ → ℝ) (M : Set ℝ) (x : ℝ) (hux : Tendsto u atTop (𝓝 x)) (huM : ∀ᶠ n in atTop, u n ∈ M) : x ∈ closure M := mem_closure_iff_clusterPt.mpr (neBot_of_le <| le_inf hux <| le_principal_iff.mpr huM)
-
-
-
@@ -0,0 +1,371 @@import Mathlib.Topology.Instances.Real import Mathlib.Analysis.NormedSpace.BanachSteinhaus open Set Filter open Topology Filter variable {X : Type _} [MetricSpace X] (a b c : X) #check (dist a b : ℝ) #check (dist_nonneg : 0 ≤ dist a b) #check (dist_eq_zero : dist a b = 0 ↔ a = b) #check (dist_comm a b : dist a b = dist b a) #check (dist_triangle a b c : dist a c ≤ dist a b + dist b c) -- Note the next three lines are not quoted, their purpose is to make sure those things don't get renamed while we're looking elsewhere. #check EMetricSpace #check PseudoMetricSpace #check PseudoEMetricSpace example {u : ℕ → X} {a : X} : Tendsto u atTop (𝓝 a) ↔ ∀ ε > 0, ∃ N, ∀ n ≥ N, dist (u n) a < ε := Metric.tendsto_atTop example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} : Continuous f ↔ ∀ x : X, ∀ ε > 0, ∃ δ > 0, ∀ x', dist x' x < δ → dist (f x') (f x) < ε := Metric.continuous_iff example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := by continuity example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := continuous_dist.comp ((hf.comp continuous_fst).prod_mk (hf.comp continuous_snd)) example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := by apply Continuous.dist exact hf.comp continuous_fst exact hf.comp continuous_snd example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := (hf.comp continuous_fst).dist (hf.comp continuous_snd) example {X Y : Type _} [MetricSpace X] [MetricSpace Y] {f : X → Y} (hf : Continuous f) : Continuous fun p : X × X => dist (f p.1) (f p.2) := hf.fst'.dist hf.snd' example {f : ℝ → X} (hf : Continuous f) : Continuous fun x : ℝ => f (x ^ 2 + x) := sorry example {f : ℝ → X} (hf : Continuous f) : Continuous fun x : ℝ => f (x ^ 2 + x) := hf.comp <| (continuous_pow 2).add continuous_id example {X Y : Type _} [MetricSpace X] [MetricSpace Y] (f : X → Y) (a : X) : ContinuousAt f a ↔ ∀ ε > 0, ∃ δ > 0, ∀ {x}, dist x a < δ → dist (f x) (f a) < ε := Metric.continuousAt_iff variable (r : ℝ) example : Metric.ball a r = { b | dist b a < r } := rfl example : Metric.closedBall a r = { b | dist b a ≤ r } := rfl example (hr : 0 < r) : a ∈ Metric.ball a r := Metric.mem_ball_self hr example (hr : 0 ≤ r) : a ∈ Metric.closedBall a r := Metric.mem_closedBall_self hr example (s : Set X) : IsOpen s ↔ ∀ x ∈ s, ∃ ε > 0, Metric.ball x ε ⊆ s := Metric.isOpen_iff example {s : Set X} : IsClosed s ↔ IsOpen (sᶜ) := isOpen_compl_iff.symm example {s : Set X} (hs : IsClosed s) {u : ℕ → X} (hu : Tendsto u atTop (𝓝 a)) (hus : ∀ n, u n ∈ s) : a ∈ s := hs.mem_of_tendsto hu (eventually_of_forall hus) example {s : Set X} : a ∈ closure s ↔ ∀ ε > 0, ∃ b ∈ s, a ∈ Metric.ball b ε := Metric.mem_closure_iff example {u : ℕ → X} (hu : Tendsto u atTop (𝓝 a)) {s : Set X} (hs : ∀ n, u n ∈ s) : a ∈ closure s := sorry example {u : ℕ → X} (hu : Tendsto u atTop (𝓝 a)) {s : Set X} (hs : ∀ n, u n ∈ s) : a ∈ closure s := by rw [Metric.tendsto_atTop] at hu rw [Metric.mem_closure_iff] intro ε ε_pos rcases hu ε ε_pos with ⟨N, hN⟩ refine' ⟨u N, hs _, _⟩ rw [dist_comm] exact hN N le_rfl example {x : X} {s : Set X} : s ∈ 𝓝 x ↔ ∃ ε > 0, Metric.ball x ε ⊆ s := Metric.nhds_basis_ball.mem_iff example {x : X} {s : Set X} : s ∈ 𝓝 x ↔ ∃ ε > 0, Metric.closedBall x ε ⊆ s := Metric.nhds_basis_closedBall.mem_iff example : IsCompact (Set.Icc 0 1 : Set ℝ) := isCompact_Icc example {s : Set X} (hs : IsCompact s) {u : ℕ → X} (hu : ∀ n, u n ∈ s) : ∃ a ∈ s, ∃ φ : ℕ → ℕ, StrictMono φ ∧ Tendsto (u ∘ φ) atTop (𝓝 a) := hs.tendsto_subseq hu example {s : Set X} (hs : IsCompact s) (hs' : s.Nonempty) {f : X → ℝ} (hfs : ContinuousOn f s) : ∃ x ∈ s, ∀ y ∈ s, f x ≤ f y := hs.exists_forall_le hs' hfs example {s : Set X} (hs : IsCompact s) (hs' : s.Nonempty) {f : X → ℝ} (hfs : ContinuousOn f s) : ∃ x ∈ s, ∀ y ∈ s, f y ≤ f x := hs.exists_forall_ge hs' hfs example {s : Set X} (hs : IsCompact s) : IsClosed s := hs.isClosed example {X : Type _} [MetricSpace X] [CompactSpace X] : IsCompact (univ : Set X) := isCompact_univ #check IsCompact.isClosed example {X : Type _} [MetricSpace X] {Y : Type _} [MetricSpace Y] {f : X → Y} : UniformContinuous f ↔ ∀ ε > 0, ∃ δ > 0, ∀ {a b : X}, dist a b < δ → dist (f a) (f b) < ε := Metric.uniformContinuous_iff example {X : Type _} [MetricSpace X] [CompactSpace X] {Y : Type _} [MetricSpace Y] {f : X → Y} (hf : Continuous f) : UniformContinuous f := sorry example {X : Type _} [MetricSpace X] [CompactSpace X] {Y : Type _} [MetricSpace Y] {f : X → Y} (hf : Continuous f) : UniformContinuous f := by rw [Metric.uniformContinuous_iff] intro ε ε_pos let φ : X × X → ℝ := fun p => dist (f p.1) (f p.2) have φ_cont : Continuous φ := hf.fst'.dist hf.snd' let K := { p : X × X | ε ≤ φ p } have K_closed : IsClosed K := isClosed_le continuous_const φ_cont have K_cpct : IsCompact K := K_closed.isCompact cases' eq_empty_or_nonempty K with hK hK · use 1, by norm_num intro x y _ have : (x, y) ∉ K := by simp [hK] simpa using this · rcases K_cpct.exists_forall_le hK continuous_dist.continuousOn with ⟨⟨x₀, x₁⟩, xx_in, H⟩ use dist x₀ x₁ constructor · change _ < _ rw [dist_pos] intro h have : ε ≤ 0 := by simpa [*] using xx_in linarith · intro x x' contrapose! intro hxx' exact H (x, x') hxx' example (u : ℕ → X) : CauchySeq u ↔ ∀ ε > 0, ∃ N : ℕ, ∀ m ≥ N, ∀ n ≥ N, dist (u m) (u n) < ε := Metric.cauchySeq_iff example (u : ℕ → X) : CauchySeq u ↔ ∀ ε > 0, ∃ N : ℕ, ∀ n ≥ N, dist (u n) (u N) < ε := Metric.cauchySeq_iff' example [CompleteSpace X] (u : ℕ → X) (hu : CauchySeq u) : ∃ x, Tendsto u atTop (𝓝 x) := cauchySeq_tendsto_of_complete hu open BigOperators open Finset theorem cauchySeq_of_le_geometric_two' {u : ℕ → X} (hu : ∀ n : ℕ, dist (u n) (u (n + 1)) ≤ (1 / 2) ^ n) : CauchySeq u := by rw [Metric.cauchySeq_iff'] intro ε ε_pos obtain ⟨N, hN⟩ : ∃ N : ℕ, 1 / 2 ^ N * 2 < ε := by sorry use N intro n hn obtain ⟨k, rfl : n = N + k⟩ := le_iff_exists_add.mp hn calc dist (u (N + k)) (u N) = dist (u (N + 0)) (u (N + k)) := sorry _ ≤ ∑ i in range k, dist (u (N + i)) (u (N + (i + 1))) := sorry _ ≤ ∑ i in range k, (1 / 2 : ℝ) ^ (N + i) := sorry _ = 1 / 2 ^ N * ∑ i in range k, (1 / 2) ^ i := sorry _ ≤ 1 / 2 ^ N * 2 := sorry _ < ε := sorry example {u : ℕ → X} (hu : ∀ n : ℕ, dist (u n) (u (n + 1)) ≤ (1 / 2) ^ n) : CauchySeq u := by rw [Metric.cauchySeq_iff'] intro ε ε_pos obtain ⟨N, hN⟩ : ∃ N : ℕ, 1 / 2 ^ N * 2 < ε := by have : Tendsto (fun N : ℕ => (1 / 2 ^ N * 2 : ℝ)) atTop (𝓝 0) := by rw [← MulZeroClass.zero_mul (2 : ℝ)] apply Tendsto.mul simp_rw [← one_div_pow (2 : ℝ)] apply tendsto_pow_atTop_nhds_0_of_lt_1 <;> linarith exact tendsto_const_nhds rcases(atTop_basis.tendsto_iff (nhds_basis_Ioo_pos (0 : ℝ))).mp this ε ε_pos with ⟨N, _, hN⟩ exact ⟨N, by simpa using (hN N left_mem_Ici).2⟩ use N intro n hn obtain ⟨k, rfl : n = N + k⟩ := le_iff_exists_add.mp hn calc dist (u (N + k)) (u N) = dist (u (N + 0)) (u (N + k)) := by rw [dist_comm, add_zero] _ ≤ ∑ i in range k, dist (u (N + i)) (u (N + (i + 1))) := (dist_le_range_sum_dist (fun i => u (N + i)) k) _ ≤ ∑ i in range k, (1 / 2 : ℝ) ^ (N + i) := (sum_le_sum fun i _ => hu <| N + i) _ = 1 / 2 ^ N * ∑ i in range k, (1 / 2 : ℝ) ^ i := by simp_rw [← one_div_pow, pow_add, ← mul_sum] _ ≤ 1 / 2 ^ N * 2 := (mul_le_mul_of_nonneg_left (sum_geometric_two_le _) (one_div_nonneg.mpr (pow_nonneg (zero_le_two : (0 : ℝ) ≤ 2) _))) _ < ε := hN open Metric example [CompleteSpace X] (f : ℕ → Set X) (ho : ∀ n, IsOpen (f n)) (hd : ∀ n, Dense (f n)) : Dense (⋂ n, f n) := by let B : ℕ → ℝ := fun n => (1 / 2) ^ n have Bpos : ∀ n, 0 < B n sorry /- Translate the density assumption into two functions `center` and `radius` associating to any n, x, δ, δpos a center and a positive radius such that `closedBall center radius` is included both in `f n` and in `closedBall x δ`. We can also require `radius ≤ (1/2)^(n+1)`, to ensure we get a Cauchy sequence later. -/ have : ∀ (n : ℕ) (x : X), ∀ δ > 0, ∃ y : X, ∃ r > 0, r ≤ B (n + 1) ∧ closedBall y r ⊆ closedBall x δ ∩ f n := by sorry choose! center radius Hpos HB Hball using this intro x rw [mem_closure_iff_nhds_basis nhds_basis_closedBall] intro ε εpos /- `ε` is positive. We have to find a point in the ball of radius `ε` around `x` belonging to all `f n`. For this, we construct inductively a sequence `F n = (c n, r n)` such that the closed ball `closedBall (c n) (r n)` is included in the previous ball and in `f n`, and such that `r n` is small enough to ensure that `c n` is a Cauchy sequence. Then `c n` converges to a limit which belongs to all the `f n`. -/ let F : ℕ → X × ℝ := fun n => Nat.recOn n (Prod.mk x (min ε (B 0))) fun n p => Prod.mk (center n p.1 p.2) (radius n p.1 p.2) let c : ℕ → X := fun n => (F n).1 let r : ℕ → ℝ := fun n => (F n).2 have rpos : ∀ n, 0 < r n := by sorry have rB : ∀ n, r n ≤ B n := by sorry have incl : ∀ n, closedBall (c (n + 1)) (r (n + 1)) ⊆ closedBall (c n) (r n) ∩ f n := by sorry have cdist : ∀ n, dist (c n) (c (n + 1)) ≤ B n := by sorry have : CauchySeq c := cauchySeq_of_le_geometric_two' cdist -- as the sequence `c n` is Cauchy in a complete space, it converges to a limit `y`. rcases cauchySeq_tendsto_of_complete this with ⟨y, ylim⟩ -- this point `y` will be the desired point. We will check that it belongs to all -- `f n` and to `ball x ε`. use y have I : ∀ n, ∀ m ≥ n, closedBall (c m) (r m) ⊆ closedBall (c n) (r n) := by sorry have yball : ∀ n, y ∈ closedBall (c n) (r n) := by sorry sorry example [CompleteSpace X] (f : ℕ → Set X) (ho : ∀ n, IsOpen (f n)) (hd : ∀ n, Dense (f n)) : Dense (⋂ n, f n) := by let B : ℕ → ℝ := fun n => (1 / 2) ^ n have Bpos : ∀ n, 0 < B n := fun n => pow_pos sorry n /- Translate the density assumption into two functions `center` and `radius` associating to any n, x, δ, δpos a center and a positive radius such that `closedBall center radius` is included both in `f n` and in `closedBall x δ`. We can also require `radius ≤ (1/2)^(n+1)`, to ensure we get a Cauchy sequence later. -/ have : ∀ (n : ℕ) (x : X), ∀ δ > 0, ∃ y : X, ∃ r > 0, r ≤ B (n + 1) ∧ closedBall y r ⊆ closedBall x δ ∩ f n := by intro n x δ δpos have : x ∈ closure (f n) := hd n x rcases Metric.mem_closure_iff.1 this (δ / 2) (half_pos δpos) with ⟨y, ys, xy⟩ rw [dist_comm] at xy obtain ⟨r, rpos, hr⟩ : ∃ r > 0, closedBall y r ⊆ f n := nhds_basis_closedBall.mem_iff.1 (isOpen_iff_mem_nhds.1 (ho n) y ys) refine' ⟨y, min (min (δ / 2) r) (B (n + 1)), _, _, fun z hz => ⟨_, _⟩⟩ show 0 < min (min (δ / 2) r) (B (n + 1)) exact lt_min (lt_min (half_pos δpos) rpos) (Bpos (n + 1)) show min (min (δ / 2) r) (B (n + 1)) ≤ B (n + 1) exact min_le_right _ _ show z ∈ closedBall x δ exact calc dist z x ≤ dist z y + dist y x := dist_triangle _ _ _ _ ≤ min (min (δ / 2) r) (B (n + 1)) + δ / 2 := (add_le_add hz xy.le) _ ≤ δ / 2 + δ / 2 := (add_le_add_right ((min_le_left _ _).trans (min_le_left _ _)) _) _ = δ := add_halves δ show z ∈ f n exact hr (calc dist z y ≤ min (min (δ / 2) r) (B (n + 1)) := hz _ ≤ r := (min_le_left _ _).trans (min_le_right _ _) ) choose! center radius Hpos HB Hball using this refine' fun x => (mem_closure_iff_nhds_basis nhds_basis_closedBall).2 fun ε εpos => _ /- `ε` is positive. We have to find a point in the ball of radius `ε` around `x` belonging to all `f n`. For this, we construct inductively a sequence `F n = (c n, r n)` such that the closed ball `closedBall (c n) (r n)` is included in the previous ball and in `f n`, and such that `r n` is small enough to ensure that `c n` is a Cauchy sequence. Then `c n` converges to a limit which belongs to all the `f n`. -/ let F : ℕ → X × ℝ := fun n => Nat.recOn n (Prod.mk x (min ε (B 0))) fun n p => Prod.mk (center n p.1 p.2) (radius n p.1 p.2) let c : ℕ → X := fun n => (F n).1 let r : ℕ → ℝ := fun n => (F n).2 have rpos : ∀ n, 0 < r n := by intro n induction' n with n hn exact lt_min εpos (Bpos 0) exact Hpos n (c n) (r n) hn have rB : ∀ n, r n ≤ B n := by intro n induction' n with n hn exact min_le_right _ _ exact HB n (c n) (r n) (rpos n) have incl : ∀ n, closedBall (c (n + 1)) (r (n + 1)) ⊆ closedBall (c n) (r n) ∩ f n := fun n => Hball n (c n) (r n) (rpos n) have cdist : ∀ n, dist (c n) (c (n + 1)) ≤ B n := by intro n rw [dist_comm] have A : c (n + 1) ∈ closedBall (c (n + 1)) (r (n + 1)) := mem_closedBall_self (rpos <| n + 1).le have I := calc closedBall (c (n + 1)) (r (n + 1)) ⊆ closedBall (c n) (r n) := (incl n).trans (inter_subset_left _ _) _ ⊆ closedBall (c n) (B n) := closedBall_subset_closedBall (rB n) exact I A have : CauchySeq c := cauchySeq_of_le_geometric_two' cdist -- as the sequence `c n` is Cauchy in a complete space, it converges to a limit `y`. rcases cauchySeq_tendsto_of_complete this with ⟨y, ylim⟩ -- this point `y` will be the desired point. We will check that it belongs to all -- `f n` and to `ball x ε`. use y have I : ∀ n, ∀ m ≥ n, closedBall (c m) (r m) ⊆ closedBall (c n) (r n) := by intro n refine' Nat.le_induction _ fun m hnm h => _ · exact Subset.rfl · exact (incl m).trans ((Set.inter_subset_left _ _).trans h) have yball : ∀ n, y ∈ closedBall (c n) (r n) := by intro n refine' isClosed_ball.mem_of_tendsto ylim _ refine' (Filter.eventually_ge_atTop n).mono fun m hm => _ exact I n m hm (mem_closedBall_self (rpos _).le) constructor · suffices ∀ n, y ∈ f n by rwa [Set.mem_iInter] intro n have : closedBall (c (n + 1)) (r (n + 1)) ⊆ f n := Subset.trans (incl n) (inter_subset_right _ _) exact this (yball (n + 1)) calc dist y x ≤ r 0 := yball 0 _ ≤ ε := min_le_left _ _
-
-
-
@@ -0,0 +1,207 @@import Mathlib.Topology.Instances.Real import Mathlib.Analysis.NormedSpace.BanachSteinhaus open Set Filter Topology section variable {X : Type _} [TopologicalSpace X] example : IsOpen (univ : Set X) := isOpen_univ example : IsOpen (∅ : Set X) := isOpen_empty example {ι : Type _} {s : ι → Set X} (hs : ∀ i, IsOpen <| s i) : IsOpen (⋃ i, s i) := isOpen_iUnion hs example {ι : Type _} [Fintype ι] {s : ι → Set X} (hs : ∀ i, IsOpen <| s i) : IsOpen (⋂ i, s i) := isOpen_iInter hs variable {Y : Type _} [TopologicalSpace Y] example {f : X → Y} : Continuous f ↔ ∀ s, IsOpen s → IsOpen (f ⁻¹' s) := continuous_def example {f : X → Y} {x : X} : ContinuousAt f x ↔ map f (𝓝 x) ≤ 𝓝 (f x) := Iff.rfl example {f : X → Y} {x : X} : ContinuousAt f x ↔ ∀ U ∈ 𝓝 (f x), ∀ᶠ x in 𝓝 x, f x ∈ U := Iff.rfl example {x : X} {s : Set X} : s ∈ 𝓝 x ↔ ∃ t, t ⊆ s ∧ IsOpen t ∧ x ∈ t := mem_nhds_iff example (x : X) : pure x ≤ 𝓝 x := pure_le_nhds x example (x : X) (P : X → Prop) (h : ∀ᶠ y in 𝓝 x, P y) : P x := pure_le_nhds x h example {P : X → Prop} {x : X} (h : ∀ᶠ y in 𝓝 x, P y) : ∀ᶠ y in 𝓝 x, ∀ᶠ z in 𝓝 y, P z := eventually_eventually_nhds.mpr h #check TopologicalSpace.mkOfNhds #check TopologicalSpace.nhds_mkOfNhds example {α : Type _} (n : α → Filter α) (H₀ : ∀ a, pure a ≤ n a) (H : ∀ a : α, ∀ p : α → Prop, (∀ᶠ x in n a, p x) → ∀ᶠ y in n a, ∀ᶠ x in n y, p x) : ∀ a, ∀ s ∈ n a, ∃ t ∈ n a, t ⊆ s ∧ ∀ a' ∈ t, s ∈ n a' := sorry example {α : Type _} (n : α → Filter α) (H₀ : ∀ a, pure a ≤ n a) (H : ∀ a : α, ∀ p : α → Prop, (∀ᶠ x in n a, p x) → ∀ᶠ y in n a, ∀ᶠ x in n y, p x) : ∀ a, ∀ s ∈ n a, ∃ t ∈ n a, t ⊆ s ∧ ∀ a' ∈ t, s ∈ n a' := by intro a s s_in refine' ⟨{ y | s ∈ n y }, H a (fun x => x ∈ s) s_in, _, by tauto⟩ rintro y (hy : s ∈ n y) exact H₀ y hy end -- BOTH. variable {X Y : Type _} example (f : X → Y) : TopologicalSpace X → TopologicalSpace Y := TopologicalSpace.coinduced f example (f : X → Y) : TopologicalSpace Y → TopologicalSpace X := TopologicalSpace.induced f example (f : X → Y) (T_X : TopologicalSpace X) (T_Y : TopologicalSpace Y) : TopologicalSpace.coinduced f T_X ≤ T_Y ↔ T_X ≤ TopologicalSpace.induced f T_Y := coinduced_le_iff_le_induced #check coinduced_compose #check induced_compose example {T T' : TopologicalSpace X} : T ≤ T' ↔ ∀ s, T'.IsOpen s → T.IsOpen s := Iff.rfl example (T_X : TopologicalSpace X) (T_Y : TopologicalSpace Y) (f : X → Y) : Continuous f ↔ TopologicalSpace.coinduced f T_X ≤ T_Y := continuous_iff_coinduced_le example {Z : Type _} (f : X → Y) (T_X : TopologicalSpace X) (T_Z : TopologicalSpace Z) (g : Y → Z) : @Continuous Y Z (TopologicalSpace.coinduced f T_X) T_Z g ↔ @Continuous X Z T_X T_Z (g ∘ f) := by rw [continuous_iff_coinduced_le, coinduced_compose, continuous_iff_coinduced_le] example (ι : Type _) (X : ι → Type _) (T_X : ∀ i, TopologicalSpace <| X i) : (Pi.topologicalSpace : TopologicalSpace (∀ i, X i)) = ⨅ i, TopologicalSpace.induced (fun x => x i) (T_X i) := rfl example [TopologicalSpace X] [T2Space X] {u : ℕ → X} {a b : X} (ha : Tendsto u atTop (𝓝 a)) (hb : Tendsto u atTop (𝓝 b)) : a = b := tendsto_nhds_unique ha hb example [TopologicalSpace X] [RegularSpace X] (a : X) : (𝓝 a).HasBasis (fun s : Set X => s ∈ 𝓝 a ∧ IsClosed s) id := closed_nhds_basis a example [TopologicalSpace X] {x : X} : (𝓝 x).HasBasis (fun t : Set X => t ∈ 𝓝 x ∧ IsOpen t) id := nhds_basis_opens' x theorem aux {X Y A : Type _} [TopologicalSpace X] {c : A → X} {f : A → Y} {x : X} {F : Filter Y} (h : Tendsto f (comap c (𝓝 x)) F) {V' : Set Y} (V'_in : V' ∈ F) : ∃ V ∈ 𝓝 x, IsOpen V ∧ c ⁻¹' V ⊆ f ⁻¹' V' := sorry example {X Y A : Type _} [TopologicalSpace X] {c : A → X} {f : A → Y} {x : X} {F : Filter Y} (h : Tendsto f (comap c (𝓝 x)) F) {V' : Set Y} (V'_in : V' ∈ F) : ∃ V ∈ 𝓝 x, IsOpen V ∧ c ⁻¹' V ⊆ f ⁻¹' V' := by simpa [and_assoc] using ((nhds_basis_opens' x).comap c).tendsto_left_iff.mp h V' V'_in example [TopologicalSpace X] [TopologicalSpace Y] [RegularSpace Y] {A : Set X} (hA : ∀ x, x ∈ closure A) {f : A → Y} (f_cont : Continuous f) (hf : ∀ x : X, ∃ c : Y, Tendsto f (comap (↑) <| 𝓝 x) <| 𝓝 c) : ∃ φ : X → Y, Continuous φ ∧ ∀ a : A, φ a = f a := sorry #check @HasBasis.tendsto_right_iff example [TopologicalSpace X] [TopologicalSpace Y] [T3Space Y] {A : Set X} (hA : ∀ x, x ∈ closure A) {f : A → Y} (f_cont : Continuous f) (hf : ∀ x : X, ∃ c : Y, Tendsto f (comap (↑) <| 𝓝 x) <| 𝓝 c) : ∃ φ : X → Y, Continuous φ ∧ ∀ a : A, φ a = f a := by choose φ hφ using hf use φ constructor · rw [continuous_iff_continuousAt] intro x suffices ∀ V' ∈ 𝓝 (φ x), IsClosed V' → φ ⁻¹' V' ∈ 𝓝 x by simpa [ContinuousAt, (closed_nhds_basis (φ x)).tendsto_right_iff] intro V' V'_in V'_closed obtain ⟨V, V_in, V_op, hV⟩ : ∃ V ∈ 𝓝 x, IsOpen V ∧ (↑) ⁻¹' V ⊆ f ⁻¹' V' := aux (hφ x) V'_in suffices : ∀ y ∈ V, φ y ∈ V' exact mem_of_superset V_in this intro y y_in have hVx : V ∈ 𝓝 y := V_op.mem_nhds y_in haveI : (comap ((↑) : A → X) (𝓝 y)).NeBot := by simpa [mem_closure_iff_comap_neBot] using hA y apply V'_closed.mem_of_tendsto (hφ y) exact mem_of_superset (preimage_mem_comap hVx) hV · intro a have lim : Tendsto f (𝓝 a) (𝓝 <| φ a) := by simpa [nhds_induced] using hφ a exact tendsto_nhds_unique lim f_cont.continuousAt example [TopologicalSpace X] [TopologicalSpace.FirstCountableTopology X] {s : Set X} {a : X} : a ∈ closure s ↔ ∃ u : ℕ → X, (∀ n, u n ∈ s) ∧ Tendsto u atTop (𝓝 a) := mem_closure_iff_seq_limit variable [TopologicalSpace X] example {F : Filter X} {x : X} : ClusterPt x F ↔ NeBot (𝓝 x ⊓ F) := Iff.rfl example {s : Set X} : IsCompact s ↔ ∀ (F : Filter X) [NeBot F], F ≤ 𝓟 s → ∃ a ∈ s, ClusterPt a F := Iff.rfl example [TopologicalSpace.FirstCountableTopology X] {s : Set X} {u : ℕ → X} (hs : IsCompact s) (hu : ∀ n, u n ∈ s) : ∃ a ∈ s, ∃ φ : ℕ → ℕ, StrictMono φ ∧ Tendsto (u ∘ φ) atTop (𝓝 a) := hs.tendsto_subseq hu variable [TopologicalSpace Y] example {x : X} {F : Filter X} {G : Filter Y} (H : ClusterPt x F) {f : X → Y} (hfx : ContinuousAt f x) (hf : Tendsto f F G) : ClusterPt (f x) G := ClusterPt.map H hfx hf example [TopologicalSpace Y] {f : X → Y} (hf : Continuous f) {s : Set X} (hs : IsCompact s) : IsCompact (f '' s) := by intro F F_ne F_le have map_eq : map f (𝓟 s ⊓ comap f F) = 𝓟 (f '' s) ⊓ F := by sorry have Hne : (𝓟 s ⊓ comap f F).NeBot := by sorry have Hle : 𝓟 s ⊓ comap f F ≤ 𝓟 s := inf_le_left sorry example [TopologicalSpace Y] {f : X → Y} (hf : Continuous f) {s : Set X} (hs : IsCompact s) : IsCompact (f '' s) := by intro F F_ne F_le have map_eq : map f (𝓟 s ⊓ comap f F) = 𝓟 (f '' s) ⊓ F := by rw [Filter.push_pull, map_principal] have Hne : (𝓟 s ⊓ comap f F).NeBot := by apply NeBot.of_map rwa [map_eq, inf_of_le_right F_le] have Hle : 𝓟 s ⊓ comap f F ≤ 𝓟 s := inf_le_left rcases hs Hle with ⟨x, x_in, hx⟩ refine' ⟨f x, mem_image_of_mem f x_in, _⟩ apply hx.map hf.continuousAt rw [Tendsto, map_eq] exact inf_le_right example {ι : Type _} {s : Set X} (hs : IsCompact s) (U : ι → Set X) (hUo : ∀ i, IsOpen (U i)) (hsU : s ⊆ ⋃ i, U i) : ∃ t : Finset ι, s ⊆ ⋃ i ∈ t, U i := hs.elim_finite_subcover U hUo hsU example [CompactSpace X] : IsCompact (univ : Set X) := isCompact_univ
-
-
-
@@ -0,0 +1,40 @@import Mathlib.Analysis.SpecialFunctions.Trigonometric.Deriv import Mathlib.Analysis.Calculus.MeanValue open Set Filter open Topology Filter Classical Real noncomputable section open Real /-- The sin function has derivative 1 at 0. -/ example : HasDerivAt sin 1 0 := by simpa using hasDerivAt_sin 0 example (x : ℝ) : DifferentiableAt ℝ sin x := (hasDerivAt_sin x).differentiableAt example {f : ℝ → ℝ} {x a : ℝ} (h : HasDerivAt f a x) : deriv f x = a := h.deriv example {f : ℝ → ℝ} {x : ℝ} (h : ¬DifferentiableAt ℝ f x) : deriv f x = 0 := deriv_zero_of_not_differentiableAt h example {f g : ℝ → ℝ} {x : ℝ} (hf : DifferentiableAt ℝ f x) (hg : DifferentiableAt ℝ g x) : deriv (f + g) x = deriv f x + deriv g x := deriv_add hf hg example {f : ℝ → ℝ} {a : ℝ} (h : IsLocalMin f a) : deriv f a = 0 := h.deriv_eq_zero example {f : ℝ → ℝ} {a b : ℝ} (hab : a < b) (hfc : ContinuousOn f (Icc a b)) (hfI : f a = f b) : ∃ c ∈ Ioo a b, deriv f c = 0 := exists_deriv_eq_zero f hab hfc hfI example (f : ℝ → ℝ) {a b : ℝ} (hab : a < b) (hf : ContinuousOn f (Icc a b)) (hf' : DifferentiableOn ℝ f (Ioo a b)) : ∃ c ∈ Ioo a b, deriv f c = (f b - f a) / (b - a) := exists_deriv_eq_slope f hab hf hf' example : deriv (fun x : ℝ ↦ x ^ 5) 6 = 5 * 6 ^ 4 := by simp example : deriv sin π = -1 := by simp
-
-
-
@@ -0,0 +1,185 @@import Mathlib.Analysis.NormedSpace.BanachSteinhaus import Mathlib.Analysis.NormedSpace.FiniteDimension import Mathlib.Analysis.Calculus.Inverse import Mathlib.Analysis.Calculus.ContDiff import Mathlib.Analysis.Calculus.FDeriv.Prod open Set Filter open Topology Filter noncomputable section section variable {E : Type _} [NormedAddCommGroup E] example (x : E) : 0 ≤ ‖x‖ := norm_nonneg x example {x : E} : ‖x‖ = 0 ↔ x = 0 := norm_eq_zero example (x y : E) : ‖x + y‖ ≤ ‖x‖ + ‖y‖ := norm_add_le x y example : MetricSpace E := by infer_instance example {X : Type _} [TopologicalSpace X] {f : X → E} (hf : Continuous f) : Continuous fun x => ‖f x‖ := hf.norm variable [NormedSpace ℝ E] example (a : ℝ) (x : E) : ‖a • x‖ = |a| * ‖x‖ := norm_smul a x example [FiniteDimensional ℝ E] : CompleteSpace E := by infer_instance example (𝕜 : Type _) [NontriviallyNormedField 𝕜] (x y : 𝕜) : ‖x * y‖ = ‖x‖ * ‖y‖ := norm_mul x y example (𝕜 : Type _) [NontriviallyNormedField 𝕜] : ∃ x : 𝕜, 1 < ‖x‖ := NormedField.exists_one_lt_norm 𝕜 example (𝕜 : Type _) [NontriviallyNormedField 𝕜] (E : Type _) [NormedAddCommGroup E] [NormedSpace 𝕜 E] [CompleteSpace 𝕜] [FiniteDimensional 𝕜 E] : CompleteSpace E := FiniteDimensional.complete 𝕜 E end section variable {𝕜 : Type _} [NontriviallyNormedField 𝕜] {E : Type _} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {F : Type _} [NormedAddCommGroup F] [NormedSpace 𝕜 F] example : E →L[𝕜] E := ContinuousLinearMap.id 𝕜 E example (f : E →L[𝕜] F) : E → F := f example (f : E →L[𝕜] F) : Continuous f := f.cont example (f : E →L[𝕜] F) (x y : E) : f (x + y) = f x + f y := f.map_add x y example (f : E →L[𝕜] F) (a : 𝕜) (x : E) : f (a • x) = a • f x := f.map_smul a x variable (f : E →L[𝕜] F) example (x : E) : ‖f x‖ ≤ ‖f‖ * ‖x‖ := f.le_op_norm x example {M : ℝ} (hMp : 0 ≤ M) (hM : ∀ x, ‖f x‖ ≤ M * ‖x‖) : ‖f‖ ≤ M := f.op_norm_le_bound hMp hM end section variable {𝕜 : Type _} [NontriviallyNormedField 𝕜] {E : Type _} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {F : Type _} [NormedAddCommGroup F] [NormedSpace 𝕜 F] open Metric example {ι : Type _} [CompleteSpace E] {g : ι → E →L[𝕜] F} (h : ∀ x, ∃ C, ∀ i, ‖g i x‖ ≤ C) : ∃ C', ∀ i, ‖g i‖ ≤ C' := by -- sequence of subsets consisting of those `x : E` with norms `‖g i x‖` bounded by `n` let e : ℕ → Set E := fun n => ⋂ i : ι, { x : E | ‖g i x‖ ≤ n } -- each of these sets is closed have hc : ∀ n : ℕ, IsClosed (e n) sorry -- the union is the entire space; this is where we use `h` have hU : (⋃ n : ℕ, e n) = univ sorry /- apply the Baire category theorem to conclude that for some `m : ℕ`, `e m` contains some `x` -/ obtain ⟨m, x, hx⟩ : ∃ m, ∃ x, x ∈ interior (e m) := sorry obtain ⟨ε, ε_pos, hε⟩ : ∃ ε > 0, ball x ε ⊆ interior (e m) := sorry obtain ⟨k, hk⟩ : ∃ k : 𝕜, 1 < ‖k‖ := sorry -- show all elements in the ball have norm bounded by `m` after applying any `g i` have real_norm_le : ∀ z ∈ ball x ε, ∀ (i : ι), ‖g i z‖ ≤ m sorry have εk_pos : 0 < ε / ‖k‖ := sorry refine' ⟨(m + m : ℕ) / (ε / ‖k‖), fun i => ContinuousLinearMap.op_norm_le_of_shell ε_pos _ hk _⟩ sorry sorry end open Asymptotics open Asymptotics example {α : Type _} {E : Type _} [NormedGroup E] {F : Type _} [NormedGroup F] (c : ℝ) (l : Filter α) (f : α → E) (g : α → F) : IsBigOWith c l f g ↔ ∀ᶠ x in l, ‖f x‖ ≤ c * ‖g x‖ := isBigOWith_iff example {α : Type _} {E : Type _} [NormedGroup E] {F : Type _} [NormedGroup F] (l : Filter α) (f : α → E) (g : α → F) : f =O[l] g ↔ ∃ C, IsBigOWith C l f g := isBigO_iff_isBigOWith example {α : Type _} {E : Type _} [NormedGroup E] {F : Type _} [NormedGroup F] (l : Filter α) (f : α → E) (g : α → F) : f =o[l] g ↔ ∀ C > 0, IsBigOWith C l f g := isLittleO_iff_forall_isBigOWith example {α : Type _} {E : Type _} [NormedAddCommGroup E] (l : Filter α) (f g : α → E) : f ~[l] g ↔ (f - g) =o[l] g := Iff.rfl section variable {𝕜 : Type _} [NontriviallyNormedField 𝕜] {E : Type _} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {F : Type _} [NormedAddCommGroup F] [NormedSpace 𝕜 F] example (f : E → F) (f' : E →L[𝕜] F) (x₀ : E) : HasFDerivAt f f' x₀ ↔ (fun x => f x - f x₀ - f' (x - x₀)) =o[𝓝 x₀] fun x => x - x₀ := Iff.rfl example (f : E → F) (f' : E →L[𝕜] F) (x₀ : E) (hff' : HasFDerivAt f f' x₀) : fderiv 𝕜 f x₀ = f' := hff'.fderiv example (n : ℕ) (f : E → F) : E → E[×n]→L[𝕜] F := iteratedFDeriv 𝕜 n f example (n : WithTop ℕ) {f : E → F} : ContDiff 𝕜 n f ↔ (∀ m : ℕ, (m : WithTop ℕ) ≤ n → Continuous fun x => iteratedFDeriv 𝕜 m f x) ∧ ∀ m : ℕ, (m : WithTop ℕ) < n → Differentiable 𝕜 fun x => iteratedFDeriv 𝕜 m f x := contDiff_iff_continuous_differentiable example {𝕂 : Type _} [IsROrC 𝕂] {E : Type _} [NormedAddCommGroup E] [NormedSpace 𝕂 E] {F : Type _} [NormedAddCommGroup F] [NormedSpace 𝕂 F] {f : E → F} {x : E} {n : WithTop ℕ} (hf : ContDiffAt 𝕂 n f x) (hn : 1 ≤ n) : HasStrictFDerivAt f (fderiv 𝕂 f x) x := hf.hasStrictFDerivAt hn section LocalInverse variable [CompleteSpace E] {f : E → F} {f' : E ≃L[𝕜] F} {a : E} example (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : F → E := HasStrictFDerivAt.localInverse f f' a hf example (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : ∀ᶠ x in 𝓝 a, hf.localInverse f f' a (f x) = x := hf.eventually_left_inverse example (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : ∀ᶠ x in 𝓝 (f a), f (hf.localInverse f f' a x) = x := hf.eventually_right_inverse example [CompleteSpace E] {f : E → F} {f' : E ≃L[𝕜] F} {a : E} (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : HasStrictFDerivAt (HasStrictFDerivAt.localInverse f f' a hf) (f'.symm : F →L[𝕜] E) (f a) := HasStrictFDerivAt.to_localInverse hf end LocalInverse #check HasFDerivWithinAt #check HasFDerivAtFilter end
-
-
-
@@ -0,0 +1,8 @@import Mathlib.Analysis.SpecialFunctions.Trigonometric.Deriv import Mathlib.Analysis.Calculus.MeanValue open Set Filter open Topology Filter Classical Real noncomputable section
-
-
MIL/C09_Differential_Calculus/solutions/Solutions_S02_Differential_Calculus_in_Normed_Spaces.lean (new)
-
@@ -0,0 +1,62 @@import Mathlib.Analysis.NormedSpace.BanachSteinhaus import Mathlib.Analysis.NormedSpace.FiniteDimension import Mathlib.Analysis.Calculus.Inverse import Mathlib.Analysis.Calculus.ContDiff import Mathlib.Analysis.Calculus.FDeriv.Prod open Set Filter open Topology Filter noncomputable section section variable {𝕜 : Type _} [NontriviallyNormedField 𝕜] {E : Type _} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {F : Type _} [NormedAddCommGroup F] [NormedSpace 𝕜 F] open Metric example {ι : Type _} [CompleteSpace E] {g : ι → E →L[𝕜] F} (h : ∀ x, ∃ C, ∀ i, ‖g i x‖ ≤ C) : ∃ C', ∀ i, ‖g i‖ ≤ C' := by -- sequence of subsets consisting of those `x : E` with norms `‖g i x‖` bounded by `n` let e : ℕ → Set E := fun n => ⋂ i : ι, { x : E | ‖g i x‖ ≤ n } -- each of these sets is closed have hc : ∀ n : ℕ, IsClosed (e n) := fun i => isClosed_iInter fun i => isClosed_le (g i).cont.norm continuous_const -- the union is the entire space; this is where we use `h` have hU : (⋃ n : ℕ, e n) = univ := by refine' eq_univ_of_forall fun x => _ cases' h x with C hC obtain ⟨m, hm⟩ := exists_nat_ge C exact ⟨e m, mem_range_self m, mem_iInter.mpr fun i => le_trans (hC i) hm⟩ /- apply the Baire category theorem to conclude that for some `m : ℕ`, `e m` contains some `x` -/ obtain ⟨m : ℕ, x : E, hx : x ∈ interior (e m)⟩ := nonempty_interior_of_iUnion_of_closed hc hU obtain ⟨ε, ε_pos, hε : ball x ε ⊆ interior (e m)⟩ := isOpen_iff.mp isOpen_interior x hx obtain ⟨k : 𝕜, hk : 1 < ‖k‖⟩ := NormedField.exists_one_lt_norm 𝕜 -- show all elements in the ball have norm bounded by `m` after applying any `g i` have real_norm_le : ∀ z ∈ ball x ε, ∀ (i : ι), ‖g i z‖ ≤ m := by intro z hz i replace hz := mem_iInter.mp (interior_iInter_subset _ (hε hz)) i apply interior_subset hz have εk_pos : 0 < ε / ‖k‖ := div_pos ε_pos (zero_lt_one.trans hk) refine' ⟨(m + m : ℕ) / (ε / ‖k‖), fun i => ContinuousLinearMap.op_norm_le_of_shell ε_pos _ hk _⟩ · exact div_nonneg (Nat.cast_nonneg _) εk_pos.le intro y le_y y_lt calc ‖g i y‖ = ‖g i (y + x) - g i x‖ := by rw [(g i).map_add, add_sub_cancel] _ ≤ ‖g i (y + x)‖ + ‖g i x‖ := (norm_sub_le _ _) _ ≤ m + m := (add_le_add (real_norm_le (y + x) (by rwa [add_comm, add_mem_ball_iff_norm]) i) (real_norm_le x (mem_ball_self ε_pos) i)) _ = (m + m : ℕ) := by norm_cast _ ≤ (m + m : ℕ) * (‖y‖ / (ε / ‖k‖)) := (le_mul_of_one_le_right (Nat.cast_nonneg _) ((one_le_div <| div_pos ε_pos (zero_lt_one.trans hk)).2 le_y)) _ = (m + m : ℕ) / (ε / ‖k‖) * ‖y‖ := (mul_comm_div _ _ _).symm end
-
-
html (deleted)
-
@@ -1,1 +0,0 @@../build/html/
-
-
html/.buildinfo (new)
-
@@ -0,0 +1,4 @@# Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. config: 798c3985ff3075064f96be164dceb162 tags: 645f666f9bcd5a90fca523b33c5a78b7
-
-
-
@@ -0,0 +1,370 @@<!DOCTYPE html> <html class="writer-html5" lang="en" > <head> <meta charset="utf-8" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>1. Introduction — Mathematics in Lean 0.1 documentation</title> <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> <link rel="stylesheet" href="_static/css/custom.css" type="text/css" /> <link rel="shortcut icon" href="_static/favicon.ico"/> <!--[if lt IE 9]> <script src="_static/js/html5shiv.min.js"></script> <![endif]--> <script src="_static/jquery.js"></script> <script src="_static/_sphinx_javascript_frameworks_compat.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script src="_static/doctools.js"></script> <script src="_static/sphinx_highlight.js"></script> <script src="_static/js/theme.js"></script> <link rel="index" title="Index" href="genindex.html" /> <link rel="search" title="Search" href="search.html" /> <link rel="next" title="2. Basics" href="C02_Basics.html" /> <link rel="prev" title="Mathematics in Lean" href="index.html" /> </head> <body class="wy-body-for-nav"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search" > <a href="index.html" class="icon icon-home"> Mathematics in Lean </a> <div role="search"> <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> <ul class="current"> <li class="toctree-l1 current"><a class="current reference internal" href="#">1. Introduction</a><ul> <li class="toctree-l2"><a class="reference internal" href="#getting-started">1.1. Getting Started</a></li> <li class="toctree-l2"><a class="reference internal" href="#overview">1.2. Overview</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="C02_Basics.html">2. Basics</a></li> <li class="toctree-l1"><a class="reference internal" href="C03_Logic.html">3. Logic</a></li> <li class="toctree-l1"><a class="reference internal" href="C04_Sets_and_Functions.html">4. Sets and Functions</a></li> <li class="toctree-l1"><a class="reference internal" href="C05_Number_Theory.html">5. Number Theory</a></li> <li class="toctree-l1"><a class="reference internal" href="C06_Structures.html">6. Structures</a></li> <li class="toctree-l1"><a class="reference internal" href="C07_Hierarchies.html">7. Hierarchies</a></li> <li class="toctree-l1"><a class="reference internal" href="C08_Topology.html">8. Topology</a></li> <li class="toctree-l1"><a class="reference internal" href="C09_Differential_Calculus.html">9. Differential Calculus</a></li> </ul> <ul> <li class="toctree-l1"><a class="reference internal" href="genindex.html">Index</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="index.html">Mathematics in Lean</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="Page navigation"> <ul class="wy-breadcrumbs"> <li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li> <li class="breadcrumb-item active"><span class="section-number">1. </span>Introduction</li> <li class="wy-breadcrumbs-aside"> <a href="_sources/C01_Introduction.rst.txt" rel="nofollow"> View page source</a> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <section id="introduction"> <span id="id1"></span><h1><span class="section-number">1. </span>Introduction<a class="headerlink" href="#introduction" title="Permalink to this heading"></a></h1> <section id="getting-started"> <h2><span class="section-number">1.1. </span>Getting Started<a class="headerlink" href="#getting-started" title="Permalink to this heading"></a></h2> <p>The goal of this book is to teach you to formalize mathematics using the Lean 4 interactive proof assistant. It assumes that you know some mathematics, but it does not require much. Although we will cover examples ranging from number theory to measure theory and analysis, we will focus on elementary aspects of those fields, in the hopes that if they are not familiar to you, you can pick them up as you go. We also don’t presuppose any background in formalization. Formalization can be seen as a kind of computer programming: we will write mathematical definitions, theorems, and proofs in a regimented language, like a programming language, that Lean can understand. In return, Lean provides feedback and information, interprets expressions and guarantees that they are well-formed, and ultimately certifies the correctness of our proofs.</p> <p>You can learn more about Lean from the <a class="reference external" href="https://leanprover.github.io">Lean project page</a> and the <a class="reference external" href="https://leanprover-community.github.io/">Lean community web pages</a>. This tutorial is based on Lean’s large and ever-growing library, <em>mathlib</em>. We also strongly recommend taking a look at the <a class="reference external" href="https://leanprover.zulipchat.com/">Lean Zulip online chat group</a> if you haven’t already. You’ll find a lively and welcoming community of Lean enthusiasts there, happy to answer questions and offer moral support.</p> <p>Although you can read a pdf or html version of this book online, it designed to be read interactively, running Lean from inside the VS Code editor. To get started:</p> <ol class="arabic simple"> <li><p>Install Lean 4 and VS Code following these <a class="reference external" href="https://github.com/leanprover/lean4/blob/master/doc/quickstart.md">instructions</a>.</p></li> <li><p>In a terminal, navigate to the folder where you want to put a copy of the repository, and type <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">clone</span> <span class="pre">git@github.com:leanprover-community/mathematics_in_lean.git</span></code> to fetch it from github.</p></li> <li><p>Navigate to <code class="docutils literal notranslate"><span class="pre">mathematics_in_lean</span></code>, and execute <code class="docutils literal notranslate"><span class="pre">lake</span> <span class="pre">exe</span> <span class="pre">cache</span> <span class="pre">get</span></code> to fetch a compiled version of the library, <code class="docutils literal notranslate"><span class="pre">mathlib</span></code>.</p></li> <li><p>Type <code class="docutils literal notranslate"><span class="pre">code</span> <span class="pre">.</span></code> to open the folder in <code class="docutils literal notranslate"><span class="pre">VS</span> <span class="pre">Code</span></code>. Alternatively, you can run <code class="docutils literal notranslate"><span class="pre">VS</span> <span class="pre">Code</span></code> and choose <code class="docutils literal notranslate"><span class="pre">Open</span> <span class="pre">Folder</span></code> from the <code class="docutils literal notranslate"><span class="pre">File</span></code> menu. Be sure to open the folder <code class="docutils literal notranslate"><span class="pre">mathematics_in_lean</span></code>, not any other folder.</p></li> </ol> <p>Opening any Lean file will simultaneously open this book in a VS Code window. You can update to a newer version by tying <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">pull</span></code> followed by <code class="docutils literal notranslate"><span class="pre">lake</span> <span class="pre">exe</span> <span class="pre">cache</span> <span class="pre">get</span></code> inside the <code class="docutils literal notranslate"><span class="pre">mathematics_in_lean</span></code> folder.</p> <p>Alternatively, you can run Lean and VS Code in the cloud, using <a class="reference external" href="https://gitpod.io/">Gitpod</a>. You can find instructions as to how to do that on the Mathematics in Lean <a class="reference external" href="https://github.com/leanprover-community/mathematics_in_lean">project page</a> on Github.</p> <p>Each section in this book has an associated Lean file with examples and exercises. You can find them in the folder <cite>MIL</cite>, organized by chapter. We recommend making a copy of that folder so that you can experiment with the files as you go, while leaving the originals intact. The text will often include examples, like this one:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#eval</span> <span class="s2">"Hello, World!"</span> </pre></div> </div> <p>You should be able to find the corresponding example in the associated Lean file. If you click on the line, VS Code will show you Lean’s feedback in the <code class="docutils literal notranslate"><span class="pre">Lean</span> <span class="pre">Goal</span></code> window, and if you hover your cursor over the <code class="docutils literal notranslate"><span class="pre">#eval</span></code> command VS Code will show you Lean’s response to this command in a pop-up window. You are encouraged to edit the file and try examples of your own.</p> <p>This book moreover provides lots of challenging exercises for you to try. Don’t rush past these! Lean is about <em>doing</em> mathematics interactively, not just reading about it. Working through the exercises is central to the experience. You can always compare your solutions to the ones in the <code class="docutils literal notranslate"><span class="pre">solutions</span></code> folder associated with each section.</p> </section> <section id="overview"> <h2><span class="section-number">1.2. </span>Overview<a class="headerlink" href="#overview" title="Permalink to this heading"></a></h2> <p>Put simply, Lean is a tool for building complex expressions in a formal language known as <em>dependent type theory</em>.</p> <p id="index-0">Every expression has a <em>type</em>, and you can use the <cite>#check</cite> command to print it. Some expressions have types like <cite>ℕ</cite> or <cite>ℕ → ℕ</cite>. These are mathematical objects.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="mi">2</span> <span class="bp">+</span> <span class="mi">2</span> <span class="kd">def</span> <span class="n">f</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:=</span> <span class="n">x</span> <span class="bp">+</span> <span class="mi">3</span> <span class="k">#check</span> <span class="n">f</span> </pre></div> </div> <p>Some expressions have type <cite>Prop</cite>. These are mathematical statements.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="mi">2</span> <span class="bp">+</span> <span class="mi">2</span> <span class="bp">=</span> <span class="mi">4</span> <span class="kd">def</span> <span class="n">FermatLastTheorem</span> <span class="o">:=</span> <span class="bp">∀</span> <span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">,</span> <span class="n">n</span> <span class="bp">></span> <span class="mi">2</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp">*</span> <span class="n">y</span> <span class="bp">*</span> <span class="n">z</span> <span class="bp">≠</span> <span class="mi">0</span> <span class="bp">→</span> <span class="n">x</span> <span class="bp">^</span> <span class="n">n</span> <span class="bp">+</span> <span class="n">y</span> <span class="bp">^</span> <span class="n">n</span> <span class="bp">≠</span> <span class="n">z</span> <span class="bp">^</span> <span class="n">n</span> <span class="k">#check</span> <span class="n">FermatLastTheorem</span> </pre></div> </div> <p>Some expressions have a type, <cite>P</cite>, where <cite>P</cite> itself has type <cite>Prop</cite>. Such an expression is a proof of the proposition <cite>P</cite>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">easy</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">+</span> <span class="mi">2</span> <span class="bp">=</span> <span class="mi">4</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="k">#check</span> <span class="n">easy</span> <span class="kd">theorem</span> <span class="n">hard</span> <span class="o">:</span> <span class="n">FermatLastTheorem</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="k">#check</span> <span class="n">hard</span> </pre></div> </div> <p>If you manage to construct an expression of type <cite>fermat_last_theorem</cite> and Lean accepts it as a term of that type, you have done something very impressive. (Using <code class="docutils literal notranslate"><span class="pre">sorry</span></code> is cheating, and Lean knows it.) So now you know the game. All that is left to learn are the rules.</p> <p>This book is complementary to a companion tutorial, <a class="reference external" href="https://leanprover.github.io/theorem_proving_in_lean/">Theorem Proving in Lean</a>, which provides a more thorough introduction to the underlying logical framework and core syntax of Lean. <em>Theorem Proving in Lean</em> is for people who prefer to read a user manual cover to cover before using a new dishwasher. If you are the kind of person who prefers to hit the <em>start</em> button and figure out how to activate the potscrubber feature later, it makes more sense to start here and refer back to <em>Theorem Proving in Lean</em> as necessary.</p> <p>Another thing that distinguishes <em>Mathematics in Lean</em> from <em>Theorem Proving in Lean</em> is that here we place a much greater emphasis on the use of <em>tactics</em>. Given that we are trying to build complex expressions, Lean offers two ways of going about it: we can write down the expressions themselves (that is, suitable text descriptions thereof), or we can provide Lean with <em>instructions</em> as to how to construct them. For example, the following expression represents a proof of the fact that if <code class="docutils literal notranslate"><span class="pre">n</span></code> is even then so is <code class="docutils literal notranslate"><span class="pre">m</span> <span class="pre">*</span> <span class="pre">n</span></code>:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">Nat</span><span class="o">,</span> <span class="n">Even</span> <span class="n">n</span> <span class="bp">→</span> <span class="n">Even</span> <span class="o">(</span><span class="n">m</span> <span class="bp">*</span> <span class="n">n</span><span class="o">)</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">m</span> <span class="n">n</span> <span class="o">⟨</span><span class="n">k</span><span class="o">,</span> <span class="o">(</span><span class="n">hk</span> <span class="o">:</span> <span class="n">n</span> <span class="bp">=</span> <span class="n">k</span> <span class="bp">+</span> <span class="n">k</span><span class="o">)⟩</span> <span class="bp">=></span> <span class="k">have</span> <span class="n">hmn</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">*</span> <span class="n">n</span> <span class="bp">=</span> <span class="n">m</span> <span class="bp">*</span> <span class="n">k</span> <span class="bp">+</span> <span class="n">m</span> <span class="bp">*</span> <span class="n">k</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">hk</span><span class="o">,</span> <span class="n">mul_add</span><span class="o">]</span> <span class="k">show</span> <span class="bp">∃</span> <span class="n">l</span><span class="o">,</span> <span class="n">m</span> <span class="bp">*</span> <span class="n">n</span> <span class="bp">=</span> <span class="n">l</span> <span class="bp">+</span> <span class="n">l</span> <span class="k">from</span> <span class="o">⟨</span><span class="n">_</span><span class="o">,</span> <span class="n">hmn</span><span class="o">⟩</span> </pre></div> </div> <p>The <em>proof term</em> can be compressed to a single line:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">Nat</span><span class="o">,</span> <span class="n">Even</span> <span class="n">n</span> <span class="bp">→</span> <span class="n">Even</span> <span class="o">(</span><span class="n">m</span> <span class="bp">*</span> <span class="n">n</span><span class="o">)</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">m</span> <span class="n">n</span> <span class="o">⟨</span><span class="n">k</span><span class="o">,</span> <span class="n">hk</span><span class="o">⟩</span> <span class="bp">=></span> <span class="o">⟨</span><span class="n">m</span> <span class="bp">*</span> <span class="n">k</span><span class="o">,</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">hk</span><span class="o">,</span> <span class="n">mul_add</span><span class="o">]⟩</span> </pre></div> </div> <p>The following is, instead, a <em>tactic-style</em> proof of the same theorem:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">Nat</span><span class="o">,</span> <span class="n">Even</span> <span class="n">n</span> <span class="bp">→</span> <span class="n">Even</span> <span class="o">(</span><span class="n">m</span> <span class="bp">*</span> <span class="n">n</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="c1">-- say m and n are natural numbers, and assume n=2*k</span> <span class="n">rintro</span> <span class="n">m</span> <span class="n">n</span> <span class="o">⟨</span><span class="n">k</span><span class="o">,</span> <span class="n">hk</span><span class="o">⟩</span> <span class="c1">-- We need to prove m*n is twice a natural number. Let's show it's twice m*k.</span> <span class="n">use</span> <span class="n">m</span> <span class="bp">*</span> <span class="n">k</span> <span class="c1">-- substitute in for n</span> <span class="n">rw</span> <span class="o">[</span><span class="n">hk</span><span class="o">]</span> <span class="c1">-- and now it's obvious</span> <span class="n">ring</span> </pre></div> </div> <p>As you enter each line of such a proof in VS Code, Lean displays the <em>proof state</em> in a separate window, telling you what facts you have already established and what tasks remain to prove your theorem. You can replay the proof by stepping through the lines, since Lean will continue to show you the state of the proof at the point where the cursor is. In this example, you will then see that the first line of the proof introduces <code class="docutils literal notranslate"><span class="pre">m</span></code> and <code class="docutils literal notranslate"><span class="pre">n</span></code> (we could have renamed them at that point, if we wanted to), and also decomposes the hypothesis <code class="docutils literal notranslate"><span class="pre">Even</span> <span class="pre">n</span></code> to a <code class="docutils literal notranslate"><span class="pre">k</span></code> and the assumption that <code class="docutils literal notranslate"><span class="pre">n</span> <span class="pre">=</span> <span class="pre">2</span> <span class="pre">*</span> <span class="pre">k</span></code>. The second line, <code class="docutils literal notranslate"><span class="pre">use</span> <span class="pre">m</span> <span class="pre">*</span> <span class="pre">k</span></code>, declares that we are going to show that <code class="docutils literal notranslate"><span class="pre">m</span> <span class="pre">*</span> <span class="pre">n</span></code> is even by showing <code class="docutils literal notranslate"><span class="pre">m</span> <span class="pre">*</span> <span class="pre">n</span> <span class="pre">=</span> <span class="pre">2</span> <span class="pre">*</span> <span class="pre">(m</span> <span class="pre">*</span> <span class="pre">k)</span></code>. The next line uses the <code class="docutils literal notranslate"><span class="pre">rewrite</span></code> tactic to replace <code class="docutils literal notranslate"><span class="pre">n</span></code> by <code class="docutils literal notranslate"><span class="pre">2</span> <span class="pre">*</span> <span class="pre">k</span></code> in the goal, and the <cite>ring</cite> tactic solves the resulting goal <code class="docutils literal notranslate"><span class="pre">m</span> <span class="pre">*</span> <span class="pre">(2</span> <span class="pre">*</span> <span class="pre">k)</span> <span class="pre">=</span> <span class="pre">2</span> <span class="pre">*</span> <span class="pre">(m</span> <span class="pre">*</span> <span class="pre">k)</span></code>.</p> <p>The ability to build a proof in small steps with incremental feedback is extremely powerful. For that reason, tactic proofs are often easier and quicker to write than proof terms. There isn’t a sharp distinction between the two: tactic proofs can be inserted in proof terms, as we did with the phrase <code class="docutils literal notranslate"><span class="pre">by</span> <span class="pre">rw</span> <span class="pre">[hk,</span> <span class="pre">mul_left_comm]</span></code> in the example above. We will also see that, conversely, it is often useful to insert a short proof term in the middle of a tactic proof. That said, in this book, our emphasis will be on the use of tactics.</p> <p>In our example, the tactic proof can also be reduced to a one-liner:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">Nat</span><span class="o">,</span> <span class="n">Even</span> <span class="n">n</span> <span class="bp">→</span> <span class="n">Even</span> <span class="o">(</span><span class="n">m</span> <span class="bp">*</span> <span class="n">n</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rintro</span> <span class="n">m</span> <span class="n">n</span> <span class="o">⟨</span><span class="n">k</span><span class="o">,</span> <span class="n">hk</span><span class="o">⟩</span><span class="bp">;</span> <span class="n">use</span> <span class="n">m</span> <span class="bp">*</span> <span class="n">k</span><span class="bp">;</span> <span class="n">rw</span> <span class="o">[</span><span class="n">hk</span><span class="o">]</span><span class="bp">;</span> <span class="n">ring</span> </pre></div> </div> <p>Here we have used tactics to carry out small proof steps. But they can also provide substantial automation, and justify longer calculations and bigger inferential steps. For example, we can invoke Lean’s simplifier with specific rules for simplifying statements about parity to prove our theorem automatically.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">Nat</span><span class="o">,</span> <span class="n">Even</span> <span class="n">n</span> <span class="bp">→</span> <span class="n">Even</span> <span class="o">(</span><span class="n">m</span> <span class="bp">*</span> <span class="n">n</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intros</span><span class="bp">;</span> <span class="n">simp</span> <span class="o">[</span><span class="bp">*</span><span class="o">,</span> <span class="n">parity_simps</span><span class="o">]</span> </pre></div> </div> <p>Another big difference between the two introductions is that <em>Theorem Proving in Lean</em> depends only on core Lean and its built-in tactics, whereas <em>Mathematics in Lean</em> is built on top of Lean’s powerful and ever-growing library, <em>mathlib</em>. As a result, we can show you how to use some of the mathematical objects and theorems in the library, and some of the very useful tactics. This book is not meant to be used as an overview of the library; the <a class="reference external" href="https://leanprover-community.github.io/">community</a> web pages contain extensive documentation. Rather, our goal is to introduce you to the style of thinking that underlies that formalization, so that you are comfortable browsing the library and finding things on your own.</p> <p>Interactive theorem proving can be frustrating, and the learning curve is steep. But the Lean community is very welcoming to newcomers, and people are available on the <a class="reference external" href="https://leanprover.zulipchat.com/">Lean Zulip chat group</a> round the clock to answer questions. We hope to see you there, and have no doubt that soon enough you, too, will be able to answer such questions and contribute to the development of <em>mathlib</em>.</p> <p>So here is your mission, should you choose to accept it: dive in, try the exercises, come to Zulip with questions, and have fun. But be forewarned: interactive theorem proving will challenge you to think about mathematics and mathematical reasoning in fundamentally new ways. Your life may never be the same.</p> <p><em>Acknowledgments.</em> We are grateful to Gabriel Ebner for setting up the infrastructure for running this tutorial in VS Code, and to Scott Morrison and Mario Carneiro for help porting it from Lean 3. We are also grateful for help and corrections from Bryan Gin-ge Chen, Johan Commelin, Mathieu Guay-Paquet, Julian Külshammer, Giovanni Mascellani, Hunter Monroe, Pietro Monticone, Bartosz Piotrowski, and Guilherme Silva. Our work has been partially supported by the Hoskinson Center for Formal Mathematics.</p> </section> </section> </div> </div> <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> <a href="index.html" class="btn btn-neutral float-left" title="Mathematics in Lean" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> <a href="C02_Basics.html" class="btn btn-neutral float-right" title="2. Basics" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> </div> <hr/> <div role="contentinfo"> <p>© Copyright 2020, Jeremy Avigad, Kevin Buzzard, Robert Y. Lewis, Patrick Massot.</p> </div> Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. </footer> </div> </div> </section> </div> <script> jQuery(function () { SphinxRtdTheme.Navigation.enable(true); }); </script> </body> </html>
-
-
html/C02_Basics.html (new)
-
@@ -0,0 +1,1429 @@<!DOCTYPE html> <html class="writer-html5" lang="en" > <head> <meta charset="utf-8" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>2. Basics — Mathematics in Lean 0.1 documentation</title> <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> <link rel="stylesheet" href="_static/css/custom.css" type="text/css" /> <link rel="shortcut icon" href="_static/favicon.ico"/> <!--[if lt IE 9]> <script src="_static/js/html5shiv.min.js"></script> <![endif]--> <script src="_static/jquery.js"></script> <script src="_static/_sphinx_javascript_frameworks_compat.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script src="_static/doctools.js"></script> <script src="_static/sphinx_highlight.js"></script> <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> <script src="_static/js/theme.js"></script> <link rel="index" title="Index" href="genindex.html" /> <link rel="search" title="Search" href="search.html" /> <link rel="next" title="3. Logic" href="C03_Logic.html" /> <link rel="prev" title="1. Introduction" href="C01_Introduction.html" /> </head> <body class="wy-body-for-nav"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search" > <a href="index.html" class="icon icon-home"> Mathematics in Lean </a> <div role="search"> <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> <ul class="current"> <li class="toctree-l1"><a class="reference internal" href="C01_Introduction.html">1. Introduction</a></li> <li class="toctree-l1 current"><a class="current reference internal" href="#">2. Basics</a><ul> <li class="toctree-l2"><a class="reference internal" href="#calculating">2.1. Calculating</a></li> <li class="toctree-l2"><a class="reference internal" href="#proving-identities-in-algebraic-structures">2.2. Proving Identities in Algebraic Structures</a></li> <li class="toctree-l2"><a class="reference internal" href="#using-theorems-and-lemmas">2.3. Using Theorems and Lemmas</a></li> <li class="toctree-l2"><a class="reference internal" href="#more-on-order-and-divisibility">2.4. More on Order and Divisibility</a></li> <li class="toctree-l2"><a class="reference internal" href="#proving-facts-about-algebraic-structures">2.5. Proving Facts about Algebraic Structures</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="C03_Logic.html">3. Logic</a></li> <li class="toctree-l1"><a class="reference internal" href="C04_Sets_and_Functions.html">4. Sets and Functions</a></li> <li class="toctree-l1"><a class="reference internal" href="C05_Number_Theory.html">5. Number Theory</a></li> <li class="toctree-l1"><a class="reference internal" href="C06_Structures.html">6. Structures</a></li> <li class="toctree-l1"><a class="reference internal" href="C07_Hierarchies.html">7. Hierarchies</a></li> <li class="toctree-l1"><a class="reference internal" href="C08_Topology.html">8. Topology</a></li> <li class="toctree-l1"><a class="reference internal" href="C09_Differential_Calculus.html">9. Differential Calculus</a></li> </ul> <ul> <li class="toctree-l1"><a class="reference internal" href="genindex.html">Index</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="index.html">Mathematics in Lean</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="Page navigation"> <ul class="wy-breadcrumbs"> <li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li> <li class="breadcrumb-item active"><span class="section-number">2. </span>Basics</li> <li class="wy-breadcrumbs-aside"> <a href="_sources/C02_Basics.rst.txt" rel="nofollow"> View page source</a> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <section id="basics"> <span id="id1"></span><h1><span class="section-number">2. </span>Basics<a class="headerlink" href="#basics" title="Permalink to this heading"></a></h1> <p>This chapter is designed to introduce you to the nuts and bolts of mathematical reasoning in Lean: calculating, applying lemmas and theorems, and reasoning about generic structures.</p> <section id="calculating"> <h2><span class="section-number">2.1. </span>Calculating<a class="headerlink" href="#calculating" title="Permalink to this heading"></a></h2> <p>We generally learn to carry out mathematical calculations without thinking of them as proofs. But when we justify each step in a calculation, as Lean requires us to do, the net result is a proof that the left-hand side of the calculation is equal to the right-hand side.</p> <p id="index-0">In Lean, stating a theorem is tantamount to stating a goal, namely, the goal of proving the theorem. Lean provides the rewriting tactic <code class="docutils literal notranslate"><span class="pre">rw</span></code>, to replace the left-hand side of an identity by the right-hand side in the goal. If <code class="docutils literal notranslate"><span class="pre">a</span></code>, <code class="docutils literal notranslate"><span class="pre">b</span></code>, and <code class="docutils literal notranslate"><span class="pre">c</span></code> are real numbers, <code class="docutils literal notranslate"><span class="pre">mul_assoc</span> <span class="pre">a</span> <span class="pre">b</span> <span class="pre">c</span></code> is the identity <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">*</span> <span class="pre">b</span> <span class="pre">*</span> <span class="pre">c</span> <span class="pre">=</span> <span class="pre">a</span> <span class="pre">*</span> <span class="pre">(b</span> <span class="pre">*</span> <span class="pre">c)</span></code> and <code class="docutils literal notranslate"><span class="pre">mul_comm</span> <span class="pre">a</span> <span class="pre">b</span></code> is the identity <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">*</span> <span class="pre">b</span> <span class="pre">=</span> <span class="pre">b</span> <span class="pre">*</span> <span class="pre">a</span></code>. Lean provides automation that generally eliminates the need to refer the facts like these explicitly, but they are useful for the purposes of illustration. In Lean, multiplication associates to the left, so the left-hand side of <code class="docutils literal notranslate"><span class="pre">mul_assoc</span></code> could also be written <code class="docutils literal notranslate"><span class="pre">(a</span> <span class="pre">*</span> <span class="pre">b)</span> <span class="pre">*</span> <span class="pre">c</span></code>. However, it is generally good style to be mindful of Lean’s notational conventions and leave out parentheses when Lean does as well.</p> <p>Let’s try out <code class="docutils literal notranslate"><span class="pre">rw</span></code>.</p> <div class="highlight-lean notranslate" id="index-1"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">b</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">c</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mul_comm</span> <span class="n">a</span> <span class="n">b</span><span class="o">]</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mul_assoc</span> <span class="n">b</span> <span class="n">a</span> <span class="n">c</span><span class="o">]</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">import</span></code> line at the beginning of the example imports the theory of the real numbers from <code class="docutils literal notranslate"><span class="pre">mathlib</span></code>. For the sake of brevity, we generally suppress information like this when it is repeated from example to example.</p> <p>You are welcome to make changes to see what happens. You can type the <code class="docutils literal notranslate"><span class="pre">ℝ</span></code> character as <code class="docutils literal notranslate"><span class="pre">\R</span></code> or <code class="docutils literal notranslate"><span class="pre">\real</span></code> in VS Code. The symbol doesn’t appear until you hit space or the tab key. If you hover over a symbol when reading a Lean file, VS Code will show you the syntax that can be used to enter it. If you are curious to see all available abreviations, you can hit Ctrl-Shift-p and then type abbreviations to get access to the <code class="docutils literal notranslate"><span class="pre">Lean</span> <span class="pre">4:</span> <span class="pre">Show</span> <span class="pre">all</span> <span class="pre">abbreviations</span></code> command. If your keyboard does not have an easily accessible backslash, you can change the leading character by changing the <code class="docutils literal notranslate"><span class="pre">lean.input.leader</span></code> setting.</p> <p id="index-2">When a cursor is in the middle of a tactic proof, Lean reports on the current <em>proof state</em> in the <em>Lean infoview</em> window. As you move your cursor past each step of the proof, you can see the state change. A typical proof state in Lean might look as follows:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="mi">1</span> <span class="n">goal</span> <span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">,</span> <span class="n">h₁</span> <span class="o">:</span> <span class="n">Prime</span> <span class="n">x</span><span class="o">,</span> <span class="n">h₂</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">Even</span> <span class="n">x</span><span class="o">,</span> <span class="n">h₃</span> <span class="o">:</span> <span class="n">y</span> <span class="bp">></span> <span class="n">x</span> <span class="bp">⊢</span> <span class="n">y</span> <span class="bp">≥</span> <span class="mi">4</span> </pre></div> </div> <p>The lines before the one that begins with <code class="docutils literal notranslate"><span class="pre">⊢</span></code> denote the <em>context</em>: they are the objects and assumptions currently at play. In this example, these include two objects, <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code>, each a natural number. They also include three assumptions, labelled <code class="docutils literal notranslate"><span class="pre">h₁</span></code>, <code class="docutils literal notranslate"><span class="pre">h₂</span></code>, and <code class="docutils literal notranslate"><span class="pre">h₃</span></code>. In Lean, everything in a context is labelled with an identifier. You can type these subscripted labels as <code class="docutils literal notranslate"><span class="pre">h\1</span></code>, <code class="docutils literal notranslate"><span class="pre">h\2</span></code>, and <code class="docutils literal notranslate"><span class="pre">h\3</span></code>, but any legal identifiers would do: you can use <code class="docutils literal notranslate"><span class="pre">h1</span></code>, <code class="docutils literal notranslate"><span class="pre">h2</span></code>, <code class="docutils literal notranslate"><span class="pre">h3</span></code> instead, or <code class="docutils literal notranslate"><span class="pre">foo</span></code>, <code class="docutils literal notranslate"><span class="pre">bar</span></code>, and <code class="docutils literal notranslate"><span class="pre">baz</span></code>. The last line represents the <em>goal</em>, that is, the fact to be proved. Sometimes people use <em>target</em> for the fact to be proved, and <em>goal</em> for the combination of the context and the target. In practice, the intended meaning is usually clear.</p> <p>Try proving these identities, in each case replacing <code class="docutils literal notranslate"><span class="pre">sorry</span></code> by a tactic proof. With the <code class="docutils literal notranslate"><span class="pre">rw</span></code> tactic, you can use a left arrow (<code class="docutils literal notranslate"><span class="pre">\l</span></code>) to reverse an identity. For example, <code class="docutils literal notranslate"><span class="pre">rw</span> <span class="pre">←</span> <span class="pre">mul_assoc</span> <span class="pre">a</span> <span class="pre">b</span> <span class="pre">c</span></code> replaces <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">*</span> <span class="pre">(b</span> <span class="pre">*</span> <span class="pre">c)</span></code> by <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">*</span> <span class="pre">b</span> <span class="pre">*</span> <span class="pre">c</span></code> in the current goal. Note that the left-pointing arrow refers to going from right to left in the identity provided by <code class="docutils literal notranslate"><span class="pre">mul_assoc</span></code>, it has nothing to do with the left or right side of the goal.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">b</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">c</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="o">(</span><span class="n">b</span> <span class="bp">*</span> <span class="n">c</span><span class="o">)</span> <span class="bp">=</span> <span class="n">b</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">c</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>You can also use identities like <code class="docutils literal notranslate"><span class="pre">mul_assoc</span></code> and <code class="docutils literal notranslate"><span class="pre">mul_comm</span></code> without arguments. In this case, the rewrite tactic tries to match the left-hand side with an expression in the goal, using the first pattern it finds.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">*</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mul_assoc</span><span class="o">]</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mul_comm</span><span class="o">]</span> </pre></div> </div> <p>You can also provide <em>partial</em> information. For example, <code class="docutils literal notranslate"><span class="pre">mul_comm</span> <span class="pre">a</span></code> matches any pattern of the form <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">*</span> <span class="pre">?</span></code> and rewrites it to <code class="docutils literal notranslate"><span class="pre">?</span> <span class="pre">*</span> <span class="pre">a</span></code>. Try doing the first of these examples without providing any arguments at all, and the second with only one argument.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="o">(</span><span class="n">b</span> <span class="bp">*</span> <span class="n">c</span><span class="o">)</span> <span class="bp">=</span> <span class="n">b</span> <span class="bp">*</span> <span class="o">(</span><span class="n">c</span> <span class="bp">*</span> <span class="n">a</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="o">(</span><span class="n">b</span> <span class="bp">*</span> <span class="n">c</span><span class="o">)</span> <span class="bp">=</span> <span class="n">b</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">c</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>You an also use <code class="docutils literal notranslate"><span class="pre">rw</span></code> with facts from the local context.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="n">d</span> <span class="n">e</span> <span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">c</span> <span class="bp">*</span> <span class="n">d</span><span class="o">)</span> <span class="o">(</span><span class="n">h'</span> <span class="o">:</span> <span class="n">e</span> <span class="bp">=</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="o">(</span><span class="n">b</span> <span class="bp">*</span> <span class="n">e</span><span class="o">)</span> <span class="bp">=</span> <span class="n">c</span> <span class="bp">*</span> <span class="o">(</span><span class="n">d</span> <span class="bp">*</span> <span class="n">f</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">h'</span><span class="o">]</span> <span class="n">rw</span> <span class="o">[</span><span class="bp">←</span> <span class="n">mul_assoc</span><span class="o">]</span> <span class="n">rw</span> <span class="o">[</span><span class="n">h</span><span class="o">]</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mul_assoc</span><span class="o">]</span> </pre></div> </div> <p>Try these, using the theorem <cite>sub_self</cite> for the second one:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="n">d</span> <span class="n">e</span> <span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">e</span> <span class="bp">*</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">*</span> <span class="n">d</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">e</span> <span class="bp">*</span> <span class="n">f</span> <span class="bp">*</span> <span class="n">d</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="n">d</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">hyp</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">-</span> <span class="n">d</span><span class="o">)</span> <span class="o">(</span><span class="n">hyp'</span> <span class="o">:</span> <span class="n">d</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Multiple rewrite commands can be carried out with a single command, by listing the relevant identities separated by commas inside the square brackets.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="n">d</span> <span class="n">e</span> <span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">c</span> <span class="bp">*</span> <span class="n">d</span><span class="o">)</span> <span class="o">(</span><span class="n">h'</span> <span class="o">:</span> <span class="n">e</span> <span class="bp">=</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="o">(</span><span class="n">b</span> <span class="bp">*</span> <span class="n">e</span><span class="o">)</span> <span class="bp">=</span> <span class="n">c</span> <span class="bp">*</span> <span class="o">(</span><span class="n">d</span> <span class="bp">*</span> <span class="n">f</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">h'</span><span class="o">,</span> <span class="bp">←</span> <span class="n">mul_assoc</span><span class="o">,</span> <span class="n">h</span><span class="o">,</span> <span class="n">mul_assoc</span><span class="o">]</span> </pre></div> </div> <p>You still see the incremental progress by placing the cursor after a comma in any list of rewrites.</p> <p>Another trick is that we can declare variables once and for all outside an example or theorem. Lean then includes them automatically.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="n">d</span> <span class="n">e</span> <span class="n">f</span> <span class="n">g</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">c</span> <span class="bp">*</span> <span class="n">d</span><span class="o">)</span> <span class="o">(</span><span class="n">h'</span> <span class="o">:</span> <span class="n">e</span> <span class="bp">=</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="o">(</span><span class="n">b</span> <span class="bp">*</span> <span class="n">e</span><span class="o">)</span> <span class="bp">=</span> <span class="n">c</span> <span class="bp">*</span> <span class="o">(</span><span class="n">d</span> <span class="bp">*</span> <span class="n">f</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">h'</span><span class="o">,</span> <span class="bp">←</span> <span class="n">mul_assoc</span><span class="o">,</span> <span class="n">h</span><span class="o">,</span> <span class="n">mul_assoc</span><span class="o">]</span> </pre></div> </div> <p>Inspection of the tactic state at the beginning of the above proof reveals that Lean indeed included all variables. We can delimit the scope of the declaration by putting it in a <code class="docutils literal notranslate"><span class="pre">section</span> <span class="pre">...</span> <span class="pre">end</span></code> block. Finally, recall from the introduction that Lean provides us with a command to determine the type of an expression:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">section</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="k">#check</span> <span class="n">a</span> <span class="k">#check</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="k">#check</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="k">#check</span> <span class="n">mul_comm</span> <span class="n">a</span> <span class="n">b</span> <span class="k">#check</span> <span class="o">(</span><span class="n">mul_comm</span> <span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">a</span><span class="o">)</span> <span class="k">#check</span> <span class="n">mul_assoc</span> <span class="n">c</span> <span class="n">a</span> <span class="n">b</span> <span class="k">#check</span> <span class="n">mul_comm</span> <span class="n">a</span> <span class="k">#check</span> <span class="n">mul_comm</span> <span class="k">#check</span> <span class="bp">@</span><span class="n">mul_comm</span> <span class="kd">end</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">#check</span></code> command works for both objects and facts. In response to the command <code class="docutils literal notranslate"><span class="pre">#check</span> <span class="pre">a</span></code>, Lean reports that <code class="docutils literal notranslate"><span class="pre">a</span></code> has type <code class="docutils literal notranslate"><span class="pre">ℝ</span></code>. In response to the command <code class="docutils literal notranslate"><span class="pre">#check</span> <span class="pre">mul_comm</span> <span class="pre">a</span> <span class="pre">b</span></code>, Lean reports that <code class="docutils literal notranslate"><span class="pre">mul_comm</span> <span class="pre">a</span> <span class="pre">b</span></code> is a proof of the fact <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">*</span> <span class="pre">b</span> <span class="pre">=</span> <span class="pre">b</span> <span class="pre">*</span> <span class="pre">a</span></code>. The command <code class="docutils literal notranslate"><span class="pre">#check</span> <span class="pre">(a</span> <span class="pre">:</span> <span class="pre">ℝ)</span></code> states our expectation that the type of <code class="docutils literal notranslate"><span class="pre">a</span></code> is <code class="docutils literal notranslate"><span class="pre">ℝ</span></code>, and Lean will raise an error if that is not the case. We will explain the output of the last three <code class="docutils literal notranslate"><span class="pre">#check</span></code> commands later, but in the meanwhile, you can take a look at them, and experiment with some <code class="docutils literal notranslate"><span class="pre">#check</span></code> commands of your own.</p> <p>Let’s try some more examples. The theorem <code class="docutils literal notranslate"><span class="pre">two_mul</span> <span class="pre">a</span></code> says that <code class="docutils literal notranslate"><span class="pre">2</span> <span class="pre">*</span> <span class="pre">a</span> <span class="pre">=</span> <span class="pre">a</span> <span class="pre">+</span> <span class="pre">a</span></code>. The theorems <code class="docutils literal notranslate"><span class="pre">add_mul</span></code> and <code class="docutils literal notranslate"><span class="pre">mul_add</span></code> express the distributivity of multiplication over addition, and the theorem <code class="docutils literal notranslate"><span class="pre">add_assoc</span></code> expresses the associativity of addition. Use the <code class="docutils literal notranslate"><span class="pre">#check</span></code> command to see the precise statements.</p> <div class="highlight-lean notranslate" id="index-3"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="mi">2</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mul_add</span><span class="o">,</span> <span class="n">add_mul</span><span class="o">,</span> <span class="n">add_mul</span><span class="o">]</span> <span class="n">rw</span> <span class="o">[</span><span class="bp">←</span> <span class="n">add_assoc</span><span class="o">,</span> <span class="n">add_assoc</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">a</span><span class="o">)]</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mul_comm</span> <span class="n">b</span> <span class="n">a</span><span class="o">,</span> <span class="bp">←</span> <span class="n">two_mul</span><span class="o">]</span> </pre></div> </div> <p>Whereas it is possible to figure out what it going on in this proof by stepping through it in the editor, it is hard to read on its own. Lean provides a more structured way of writing proofs like this using the <code class="docutils literal notranslate"><span class="pre">calc</span></code> keyword.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="mi">2</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">b</span> <span class="o">:=</span> <span class="k">calc</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mul_add</span><span class="o">,</span> <span class="n">add_mul</span><span class="o">,</span> <span class="n">add_mul</span><span class="o">]</span> <span class="n">_</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="o">(</span><span class="n">b</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="bp">←</span> <span class="n">add_assoc</span><span class="o">,</span> <span class="n">add_assoc</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">a</span><span class="o">)]</span> <span class="n">_</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="mi">2</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mul_comm</span> <span class="n">b</span> <span class="n">a</span><span class="o">,</span> <span class="bp">←</span> <span class="n">two_mul</span><span class="o">]</span> </pre></div> </div> <p>Notice that the proof does <em>not</em> begin with <code class="docutils literal notranslate"><span class="pre">by</span></code>: an expression that begins with <code class="docutils literal notranslate"><span class="pre">calc</span></code> is a <em>proof term</em>. A <code class="docutils literal notranslate"><span class="pre">calc</span></code> expression can also be used inside a tactic proof, but Lean interprets it as the instruction to use the resulting proof term to solve the goal. The <code class="docutils literal notranslate"><span class="pre">calc</span></code> syntax is finicky: the dots and underscores and justification have to be in the format indicated above. Lean uses indentation to determine things like where a block of tactics or a <code class="docutils literal notranslate"><span class="pre">calc</span></code> block begins and ends; try changing the indentation in the proof above to see what happens.</p> <p>One way to write a <code class="docutils literal notranslate"><span class="pre">calc</span></code> proof is to outline it first using the <code class="docutils literal notranslate"><span class="pre">sorry</span></code> tactic for justification, make sure Lean accepts the expression modulo these, and then justify the individual steps using tactics.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="mi">2</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">b</span> <span class="o">:=</span> <span class="k">calc</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="n">_</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="o">(</span><span class="n">b</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="n">_</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="mi">2</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Try proving the following identity using both a pure <code class="docutils literal notranslate"><span class="pre">rw</span></code> proof and a more structured <code class="docutils literal notranslate"><span class="pre">calc</span></code> proof:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">*</span> <span class="o">(</span><span class="n">c</span> <span class="bp">+</span> <span class="n">d</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">d</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">d</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>The following exercise is a little more challenging. You can use the theorems listed underneath.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">-</span> <span class="n">b</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">-</span> <span class="n">b</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">#check</span> <span class="n">pow_two</span> <span class="n">a</span> <span class="k">#check</span> <span class="n">mul_sub</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="k">#check</span> <span class="n">add_mul</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="k">#check</span> <span class="n">add_sub</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="k">#check</span> <span class="n">sub_sub</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="k">#check</span> <span class="n">add_zero</span> <span class="n">a</span> </pre></div> </div> <p id="index-4">We can also perform rewriting in an assumption in the context. For example, <code class="docutils literal notranslate"><span class="pre">rw</span> <span class="pre">[mul_comm</span> <span class="pre">a</span> <span class="pre">b]</span> <span class="pre">at</span> <span class="pre">hyp</span></code> replaces <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">*</span> <span class="pre">b</span></code> by <code class="docutils literal notranslate"><span class="pre">b</span> <span class="pre">*</span> <span class="pre">a</span></code> in the assumption <code class="docutils literal notranslate"><span class="pre">hyp</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="n">d</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">hyp</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">d</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="o">(</span><span class="n">hyp'</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">d</span><span class="o">)</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">=</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">d</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">hyp'</span><span class="o">]</span> <span class="n">at</span> <span class="n">hyp</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mul_comm</span> <span class="n">d</span> <span class="n">a</span><span class="o">]</span> <span class="n">at</span> <span class="n">hyp</span> <span class="n">rw</span> <span class="o">[</span><span class="bp">←</span> <span class="n">two_mul</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">d</span><span class="o">)]</span> <span class="n">at</span> <span class="n">hyp</span> <span class="n">rw</span> <span class="o">[</span><span class="bp">←</span> <span class="n">mul_assoc</span> <span class="mi">2</span> <span class="n">a</span> <span class="n">d</span><span class="o">]</span> <span class="n">at</span> <span class="n">hyp</span> <span class="n">exact</span> <span class="n">hyp</span> </pre></div> </div> <p id="index-5">In the last step, the <code class="docutils literal notranslate"><span class="pre">exact</span></code> tactic can use <code class="docutils literal notranslate"><span class="pre">hyp</span></code> to solve the goal because at that point <code class="docutils literal notranslate"><span class="pre">hyp</span></code> matches the goal exactly.</p> <p id="index-6">We close this section by noting that <code class="docutils literal notranslate"><span class="pre">mathlib</span></code> provides a useful bit of automation with a <code class="docutils literal notranslate"><span class="pre">ring</span></code> tactic, which is designed to prove identities in any commutative ring as long as they follow purely from the ring axioms, without using any local assumption.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">b</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">c</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ring</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="mi">2</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ring</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">-</span> <span class="n">b</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">-</span> <span class="n">b</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ring</span> <span class="kd">example</span> <span class="o">(</span><span class="n">hyp</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">d</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="o">(</span><span class="n">hyp'</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">d</span><span class="o">)</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">=</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">d</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">hyp</span><span class="o">,</span> <span class="n">hyp'</span><span class="o">]</span> <span class="n">ring</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">ring</span></code> tactic is imported indirectly when we import <code class="docutils literal notranslate"><span class="pre">Mathlib.Data.Real.Basic</span></code>, but we will see in the next section that it can be used for calculations on structures other than the real numbers. It can be imported explicitly with the command <code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">Mathlib.Tactic</span></code>. We will see there are similar tactics for other common kind of algebraic structures.</p> <p>There is a variation of <code class="docutils literal notranslate"><span class="pre">rw</span></code> called <code class="docutils literal notranslate"><span class="pre">nth_rewrite</span></code> that allows you to replace only particular instances of an expression in the goal. Possible matches are enumerated starting with 1, so in the following example, <code class="docutils literal notranslate"><span class="pre">nth_rewrite</span> <span class="pre">2</span> <span class="pre">h</span></code> replaces the second occurrence of <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">+</span> <span class="pre">b</span></code> with <code class="docutils literal notranslate"><span class="pre">c</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">c</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">c</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">nth_rw</span> <span class="mi">2</span> <span class="o">[</span><span class="n">h</span><span class="o">]</span> <span class="n">rw</span> <span class="o">[</span><span class="n">add_mul</span><span class="o">]</span> </pre></div> </div> </section> <section id="proving-identities-in-algebraic-structures"> <span id="id2"></span><h2><span class="section-number">2.2. </span>Proving Identities in Algebraic Structures<a class="headerlink" href="#proving-identities-in-algebraic-structures" title="Permalink to this heading"></a></h2> <p id="index-7">Mathematically, a ring consists of a collection of objects, <span class="math notranslate nohighlight">\(R\)</span>, operations <span class="math notranslate nohighlight">\(+\)</span> <span class="math notranslate nohighlight">\(\times\)</span>, and constants <span class="math notranslate nohighlight">\(0\)</span> and <span class="math notranslate nohighlight">\(1\)</span>, and an operation <span class="math notranslate nohighlight">\(x \mapsto -x\)</span> such that:</p> <ul class="simple"> <li><p><span class="math notranslate nohighlight">\(R\)</span> with <span class="math notranslate nohighlight">\(+\)</span> is an <em>abelian group</em>, with <span class="math notranslate nohighlight">\(0\)</span> as the additive identity and negation as inverse.</p></li> <li><p>Multiplication is associative with identity <span class="math notranslate nohighlight">\(1\)</span>, and multiplication distributes over addition.</p></li> </ul> <p>In Lean, the collection of objects is represented as a <em>type</em>, <code class="docutils literal notranslate"><span class="pre">R</span></code>. The ring axioms are as follows:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">(</span><span class="n">R</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">)</span> <span class="o">[</span><span class="n">Ring</span> <span class="n">R</span><span class="o">]</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_assoc</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">R</span><span class="o">,</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">+</span> <span class="o">(</span><span class="n">b</span> <span class="bp">+</span> <span class="n">c</span><span class="o">))</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_comm</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">R</span><span class="o">,</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">a</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">zero_add</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">R</span><span class="o">,</span> <span class="mi">0</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">a</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_left_neg</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">R</span><span class="o">,</span> <span class="bp">-</span><span class="n">a</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">=</span> <span class="mi">0</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">mul_assoc</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">R</span><span class="o">,</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="o">(</span><span class="n">b</span> <span class="bp">*</span> <span class="n">c</span><span class="o">))</span> <span class="k">#check</span> <span class="o">(</span><span class="n">mul_one</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">R</span><span class="o">,</span> <span class="n">a</span> <span class="bp">*</span> <span class="mi">1</span> <span class="bp">=</span> <span class="n">a</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">one_mul</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">R</span><span class="o">,</span> <span class="mi">1</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">a</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">mul_add</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">R</span><span class="o">,</span> <span class="n">a</span> <span class="bp">*</span> <span class="o">(</span><span class="n">b</span> <span class="bp">+</span> <span class="n">c</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">c</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_mul</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">R</span><span class="o">,</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">c</span><span class="o">)</span> </pre></div> </div> <p>You will learn more about the square brackets in the first line later, but for the time being, suffice it to say that the declaration gives us a type, <code class="docutils literal notranslate"><span class="pre">R</span></code>, and a ring structure on <code class="docutils literal notranslate"><span class="pre">R</span></code>. Lean then allows us to use generic ring notation with elements of <code class="docutils literal notranslate"><span class="pre">R</span></code>, and to make use of a library of theorems about rings.</p> <p>The names of some of the theorems should look familiar: they are exactly the ones we used to calculate with the real numbers in the last section. Lean is good not only for proving things about concrete mathematical structures like the natural numbers and the integers, but also for proving things about abstract structures, characterized axiomatically, like rings. Moreover, Lean supports <em>generic reasoning</em> about both abstract and concrete structures, and can be trained to recognized appropriate instances. So any theorem about rings can be applied to concrete rings like the integers, <code class="docutils literal notranslate"><span class="pre">ℤ</span></code>, the rational numbers, <code class="docutils literal notranslate"><span class="pre">ℚ</span></code>, and the complex numbers <code class="docutils literal notranslate"><span class="pre">ℂ</span></code>. It can also be applied to any instance of an abstract structure that extends rings, such as any <em>ordered ring</em> or any <em>field</em>.</p> <p id="index-8">Not all important properties of the real numbers hold in an arbitrary ring, however. For example, multiplication on the real numbers is commutative, but that does not hold in general. If you have taken a course in linear algebra, you will recognize that, for every <span class="math notranslate nohighlight">\(n\)</span>, the <span class="math notranslate nohighlight">\(n\)</span> by <span class="math notranslate nohighlight">\(n\)</span> matrices of real numbers form a ring in which commutativity usually fails. If we declare <code class="docutils literal notranslate"><span class="pre">R</span></code> to be a <em>commutative</em> ring, in fact, all the theorems in the last section continue to hold when we replace <code class="docutils literal notranslate"><span class="pre">ℝ</span></code> by <code class="docutils literal notranslate"><span class="pre">R</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">(</span><span class="n">R</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">)</span> <span class="o">[</span><span class="n">CommRing</span> <span class="n">R</span><span class="o">]</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="n">d</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">b</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">c</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ring</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="mi">2</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ring</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">-</span> <span class="n">b</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">-</span> <span class="n">b</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ring</span> <span class="kd">example</span> <span class="o">(</span><span class="n">hyp</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">d</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="o">(</span><span class="n">hyp'</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">d</span><span class="o">)</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">=</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">d</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">hyp</span><span class="o">,</span> <span class="n">hyp'</span><span class="o">]</span> <span class="n">ring</span> </pre></div> </div> <p>We leave it to you to check that all the other proofs go through unchanged. Notice that when a proof is short, like <code class="docutils literal notranslate"><span class="pre">by</span> <span class="pre">ring</span></code> or <code class="docutils literal notranslate"><span class="pre">by</span> <span class="pre">linarith</span></code> or <code class="docutils literal notranslate"><span class="pre">by</span> <span class="pre">sorry</span></code>, it is common (and permissible) to put it on the same line as the <code class="docutils literal notranslate"><span class="pre">by</span></code>. Good proof-writing style should strike a balance between concision and readability.</p> <p>The goal of this section is to strengthen the skills you have developed in the last section and apply them to reasoning axiomatically about rings. We will start with the axioms listed above, and use them to derive other facts. Most of the facts we prove are already in <code class="docutils literal notranslate"><span class="pre">mathlib</span></code>. We will give the versions we prove the same names to help you learn the contents of the library as well as the naming conventions.</p> <p id="index-9">Lean provides an organizational mechanism similar to those used in programming languages: when a definition or theorem <code class="docutils literal notranslate"><span class="pre">foo</span></code> is introduced in a <em>namespace</em> <code class="docutils literal notranslate"><span class="pre">bar</span></code>, its full name is <code class="docutils literal notranslate"><span class="pre">bar.foo</span></code>. The command <code class="docutils literal notranslate"><span class="pre">open</span> <span class="pre">bar</span></code> later <em>opens</em> the namespace, which allows us to use the shorter name <code class="docutils literal notranslate"><span class="pre">foo</span></code>. To avoid errors due to name clashes, in the next example we put our versions of the library theorems in a new namespace called <code class="docutils literal notranslate"><span class="pre">MyRing.</span></code></p> <p>The next example shows that we do not need <code class="docutils literal notranslate"><span class="pre">add_zero</span></code> or <code class="docutils literal notranslate"><span class="pre">add_right_neg</span></code> as ring axioms, because they follow from the other axioms.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">namespace</span> <span class="n">MyRing</span> <span class="kd">variable</span> <span class="o">{</span><span class="n">R</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">Ring</span> <span class="n">R</span><span class="o">]</span> <span class="kd">theorem</span> <span class="n">add_zero</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">+</span> <span class="mi">0</span> <span class="bp">=</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">add_comm</span><span class="o">,</span> <span class="n">zero_add</span><span class="o">]</span> <span class="kd">theorem</span> <span class="n">add_right_neg</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">+</span> <span class="bp">-</span><span class="n">a</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">add_comm</span><span class="o">,</span> <span class="n">add_left_neg</span><span class="o">]</span> <span class="k">#check</span> <span class="bp">@</span><span class="n">MyRing.add_zero</span> <span class="k">#check</span> <span class="bp">@</span><span class="n">add_zero</span> <span class="kd">end</span> <span class="n">MyRing</span> </pre></div> </div> <p>The net effect is that we can temporarily reprove a theorem in the library, and then go on using the library version after that. But don’t cheat! In the exercises that follow, take care to use only the general facts about rings that we have proved earlier in this section.</p> <p>(If you are paying careful attention, you may have noticed that we changed the round brackets in <code class="docutils literal notranslate"><span class="pre">(R</span> <span class="pre">:</span> <span class="pre">Type</span> <span class="pre">_)</span></code> for curly brackets in <code class="docutils literal notranslate"><span class="pre">{R</span> <span class="pre">:</span> <span class="pre">Type</span> <span class="pre">_}</span></code>. This declares <code class="docutils literal notranslate"><span class="pre">R</span></code> to be an <em>implicit argument</em>. We will explain what this means in a moment, but don’t worry about it in the meanwhile.)</p> <p>Here is a useful theorem:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">neg_add_cancel_left</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="o">:</span> <span class="bp">-</span><span class="n">a</span> <span class="bp">+</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">=</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="bp">←</span> <span class="n">add_assoc</span><span class="o">,</span> <span class="n">add_left_neg</span><span class="o">,</span> <span class="n">zero_add</span><span class="o">]</span> </pre></div> </div> <p>Prove the companion version:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">add_neg_cancel_right</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">+</span> <span class="bp">-</span><span class="n">b</span> <span class="bp">=</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Use these to prove the following:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">add_left_cancel</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">R</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">c</span><span class="o">)</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">c</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">add_right_cancel</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">R</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">c</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">c</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>With enough planning, you can do each of them with three rewrites.</p> <p id="index-10">We can now explain the use of the curly braces. Imagine you are in a situation where you have <code class="docutils literal notranslate"><span class="pre">a</span></code>, <code class="docutils literal notranslate"><span class="pre">b</span></code>, and <code class="docutils literal notranslate"><span class="pre">c</span></code> in your context, as well as a hypothesis <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">:</span> <span class="pre">a</span> <span class="pre">+</span> <span class="pre">b</span> <span class="pre">=</span> <span class="pre">a</span> <span class="pre">+</span> <span class="pre">c</span></code>, and you would like to draw the conclusion <code class="docutils literal notranslate"><span class="pre">b</span> <span class="pre">=</span> <span class="pre">c</span></code>. In Lean, you can apply a theorem to hypotheses and facts just the same way that you can apply them to objects, so you might think that <code class="docutils literal notranslate"><span class="pre">add_left_cancel</span> <span class="pre">a</span> <span class="pre">b</span> <span class="pre">c</span> <span class="pre">h</span></code> is a proof of the fact <code class="docutils literal notranslate"><span class="pre">b</span> <span class="pre">=</span> <span class="pre">c</span></code>. But notice that explicitly writing <code class="docutils literal notranslate"><span class="pre">a</span></code>, <code class="docutils literal notranslate"><span class="pre">b</span></code>, and <code class="docutils literal notranslate"><span class="pre">c</span></code> is redundant, because the hypothesis <code class="docutils literal notranslate"><span class="pre">h</span></code> makes it clear that those are the objects we have in mind. In this case, typing a few extra characters is not onerous, but if we wanted to apply <code class="docutils literal notranslate"><span class="pre">add_left_cancel</span></code> to more complicated expressions, writing them would be tedious. In cases like these, Lean allows us to mark arguments as <em>implicit</em>, meaning that they are supposed to be left out and inferred by other means, such as later arguments and hypotheses. The curly brackets in <code class="docutils literal notranslate"><span class="pre">{a</span> <span class="pre">b</span> <span class="pre">c</span> <span class="pre">:</span> <span class="pre">R}</span></code> do exactly that. So, given the statement of the theorem above, the correct expression is simply <code class="docutils literal notranslate"><span class="pre">add_left_cancel</span> <span class="pre">h</span></code>.</p> <p>To illustrate, let us show that <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">*</span> <span class="pre">0</span> <span class="pre">=</span> <span class="pre">0</span></code> follows from the ring axioms.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">mul_zero</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="mi">0</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="k">have</span> <span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="mi">0</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">*</span> <span class="mi">0</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="mi">0</span> <span class="bp">+</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="bp">←</span> <span class="n">mul_add</span><span class="o">,</span> <span class="n">add_zero</span><span class="o">,</span> <span class="n">add_zero</span><span class="o">]</span> <span class="n">rw</span> <span class="o">[</span><span class="n">add_left_cancel</span> <span class="n">h</span><span class="o">]</span> </pre></div> </div> <p id="index-11">We have used a new trick! If you step through the proof, you can see what is going on. The <code class="docutils literal notranslate"><span class="pre">have</span></code> tactic introduces a new goal, <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">*</span> <span class="pre">0</span> <span class="pre">+</span> <span class="pre">a</span> <span class="pre">*</span> <span class="pre">0</span> <span class="pre">=</span> <span class="pre">a</span> <span class="pre">*</span> <span class="pre">0</span> <span class="pre">+</span> <span class="pre">0</span></code>, with the same context as the original goal. The fact that the next line is indented indicates that Lean is expecting a block of tactics that serves to prove this new goal. The indentation therefore promotes a modular style of proof: the indented subproof establishes the goal that was introduced by the <code class="docutils literal notranslate"><span class="pre">have</span></code>. After that, we are back to proving the original goal, except a new hypothesis <code class="docutils literal notranslate"><span class="pre">h</span></code> has been added: having proved it, we are now free to use it. At this point, the goal is exactly the result of <code class="docutils literal notranslate"><span class="pre">add_left_cancel</span> <span class="pre">h</span></code>. We could equally well have closed the proof with <code class="docutils literal notranslate"><span class="pre">apply</span> <span class="pre">add_left_cancel</span> <span class="pre">h</span></code> or <code class="docutils literal notranslate"><span class="pre">exact</span> <span class="pre">add_left_cancel</span> <span class="pre">h</span></code>.</p> <p>Remember that multiplication is not assumed to be commutative, so the following theorem also requires some work.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">zero_mul</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>By now, you should also be able replace each <code class="docutils literal notranslate"><span class="pre">sorry</span></code> in the next exercise with a proof, still using only facts about rings that we have established in this section.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">neg_eq_of_add_eq_zero</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">R</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="bp">-</span><span class="n">a</span> <span class="bp">=</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">eq_neg_of_add_eq_zero</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">R</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">=</span> <span class="bp">-</span><span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">neg_zero</span> <span class="o">:</span> <span class="o">(</span><span class="bp">-</span><span class="mi">0</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">neg_eq_of_add_eq_zero</span> <span class="n">rw</span> <span class="o">[</span><span class="n">add_zero</span><span class="o">]</span> <span class="kd">theorem</span> <span class="n">neg_neg</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="o">:</span> <span class="bp">-</span> <span class="bp">-</span><span class="n">a</span> <span class="bp">=</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>We had to use the annotation <code class="docutils literal notranslate"><span class="pre">(-0</span> <span class="pre">:</span> <span class="pre">R)</span></code> instead of <code class="docutils literal notranslate"><span class="pre">0</span></code> in the third theorem because without specifying <code class="docutils literal notranslate"><span class="pre">R</span></code> it is impossible for Lean to infer which <code class="docutils literal notranslate"><span class="pre">0</span></code> we have in mind, and by default it would be interpreted as a natural number.</p> <p>In Lean, subtraction in a ring is provably equal to addition of the additive inverse.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">-</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">+</span> <span class="bp">-</span><span class="n">b</span> <span class="o">:=</span> <span class="n">sub_eq_add_neg</span> <span class="n">a</span> <span class="n">b</span> </pre></div> </div> <p>On the real numbers, it is <em>defined</em> that way:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">-</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">+</span> <span class="bp">-</span><span class="n">b</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">-</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">+</span> <span class="bp">-</span><span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rfl</span> </pre></div> </div> <p id="index-12">The proof term <code class="docutils literal notranslate"><span class="pre">rfl</span></code> is short for <code class="docutils literal notranslate"><span class="pre">reflexivity</span></code>. Presenting it as a proof of <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">-</span> <span class="pre">b</span> <span class="pre">=</span> <span class="pre">a</span> <span class="pre">+</span> <span class="pre">-b</span></code> forces Lean to unfold the definition and recognize both sides as being the same. The <code class="docutils literal notranslate"><span class="pre">reflexivity</span></code> tactic, which can be abbreviated as <code class="docutils literal notranslate"><span class="pre">rfl</span></code>, does the same. This is an instance of what is known as a <em>definitional equality</em> in Lean’s underlying logic. This means that not only can one rewrite with <code class="docutils literal notranslate"><span class="pre">sub_eq_add_neg</span></code> to replace <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">-</span> <span class="pre">b</span> <span class="pre">=</span> <span class="pre">a</span> <span class="pre">+</span> <span class="pre">-b</span></code>, but in some contexts, when dealing with the real numbers, you can use the two sides of the equation interchangeably. For example, you now have enough information to prove the theorem <code class="docutils literal notranslate"><span class="pre">self_sub</span></code> from the last section:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">self_sub</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">-</span> <span class="n">a</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>Show that you can prove this using <code class="docutils literal notranslate"><span class="pre">rw</span></code>, but if you replace the arbitrary ring <code class="docutils literal notranslate"><span class="pre">R</span></code> by the real numbers, you can also prove it using either <code class="docutils literal notranslate"><span class="pre">apply</span></code> or <code class="docutils literal notranslate"><span class="pre">exact</span></code>.</p> <p>Lean knows that <code class="docutils literal notranslate"><span class="pre">1</span> <span class="pre">+</span> <span class="pre">1</span> <span class="pre">=</span> <span class="pre">2</span></code> holds in any ring. With a bit of effort, you can use that to prove the theorem <code class="docutils literal notranslate"><span class="pre">two_mul</span></code> from the last section:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">one_add_one_eq_two</span> <span class="o">:</span> <span class="mi">1</span> <span class="bp">+</span> <span class="mi">1</span> <span class="bp">=</span> <span class="o">(</span><span class="mi">2</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">norm_num</span> <span class="kd">theorem</span> <span class="n">two_mul</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">a</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p id="index-13">We close this section by noting that some of the facts about addition and negation that we established above do not need the full strength of the ring axioms, or even commutativity of addition. The weaker notion of a <em>group</em> can be axiomatized as follows:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">(</span><span class="n">A</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">)</span> <span class="o">[</span><span class="n">AddGroup</span> <span class="n">A</span><span class="o">]</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_assoc</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">A</span><span class="o">,</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">+</span> <span class="o">(</span><span class="n">b</span> <span class="bp">+</span> <span class="n">c</span><span class="o">))</span> <span class="k">#check</span> <span class="o">(</span><span class="n">zero_add</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">A</span><span class="o">,</span> <span class="mi">0</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">a</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_left_neg</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">A</span><span class="o">,</span> <span class="bp">-</span><span class="n">a</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">=</span> <span class="mi">0</span><span class="o">)</span> </pre></div> </div> <p>It is conventional to use additive notation when the group operation is commutative, and multiplicative notation otherwise. So Lean defines a multiplicative version as well as the additive version (and also their abelian variants, <code class="docutils literal notranslate"><span class="pre">AddCommGroup</span></code> and <code class="docutils literal notranslate"><span class="pre">CommGroup</span></code>).</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">G</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">Group</span> <span class="n">G</span><span class="o">]</span> <span class="k">#check</span> <span class="o">(</span><span class="n">mul_assoc</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">G</span><span class="o">,</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="o">(</span><span class="n">b</span> <span class="bp">*</span> <span class="n">c</span><span class="o">))</span> <span class="k">#check</span> <span class="o">(</span><span class="n">one_mul</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">G</span><span class="o">,</span> <span class="mi">1</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">a</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">mul_left_inv</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">G</span><span class="o">,</span> <span class="n">a</span><span class="bp">⁻¹</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">=</span> <span class="mi">1</span><span class="o">)</span> </pre></div> </div> <p>If you are feeling cocky, try proving the following facts about groups, using only these axioms. You will need to prove a number of helper lemmas along the way. The proofs we have carried out in this section provide some hints.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">mul_right_inv</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">G</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">a</span><span class="bp">⁻¹</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">mul_one</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">G</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="mi">1</span> <span class="bp">=</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">mul_inv_rev</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">G</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span><span class="bp">⁻¹</span> <span class="bp">=</span> <span class="n">b</span><span class="bp">⁻¹</span> <span class="bp">*</span> <span class="n">a</span><span class="bp">⁻¹</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p id="index-14">Explicitly invoking those lemmas is tedious, so mathlib provides tactics similar to <cite>ring</cite> in order to cover most uses: <cite>group</cite> is for non-commutative multiplicative groups, <cite>abel</cite> for abelian additive groups, and <cite>noncomm_ring</cite> for non-commutative groups. It may seem odd that the algebraic structures are called <cite>Ring</cite> and <cite>CommRing</cite> while the tactics are named <cite>noncomm_ring</cite> and <cite>ring</cite>. This is partly for historical reasons, but also for the convenience of using a shorter name for the tactic that deals with commutative rings, since it is used more often.</p> </section> <section id="using-theorems-and-lemmas"> <span id="id3"></span><h2><span class="section-number">2.3. </span>Using Theorems and Lemmas<a class="headerlink" href="#using-theorems-and-lemmas" title="Permalink to this heading"></a></h2> <p id="index-15">Rewriting is great for proving equations, but what about other sorts of theorems? For example, how can we prove an inequality, like the fact that <span class="math notranslate nohighlight">\(a + e^b \le a + e^c\)</span> holds whenever <span class="math notranslate nohighlight">\(b \le c\)</span>? We have already seen that theorems can be applied to arguments and hypotheses, and that the <code class="docutils literal notranslate"><span class="pre">apply</span></code> and <code class="docutils literal notranslate"><span class="pre">exact</span></code> tactics can be used to solve goals. In this section, we will make good use of these tools.</p> <p>Consider the library theorems <code class="docutils literal notranslate"><span class="pre">le_refl</span></code> and <code class="docutils literal notranslate"><span class="pre">le_trans</span></code>:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="o">(</span><span class="n">le_refl</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">,</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">a</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">le_trans</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">→</span> <span class="n">b</span> <span class="bp">≤</span> <span class="n">c</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">c</span><span class="o">)</span> </pre></div> </div> <p>As we explain in more detail in <a class="reference internal" href="C03_Logic.html#implication-and-the-universal-quantifier"><span class="std std-numref">Section 3.1</span></a>, the implicit parentheses in the statement of <code class="docutils literal notranslate"><span class="pre">le_trans</span></code> associate to the right, so it should be interpreted as <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">≤</span> <span class="pre">b</span> <span class="pre">→</span> <span class="pre">(b</span> <span class="pre">≤</span> <span class="pre">c</span> <span class="pre">→</span> <span class="pre">a</span> <span class="pre">≤</span> <span class="pre">c)</span></code>. The library designers have set the arguments to <code class="docutils literal notranslate"><span class="pre">le_trans</span></code> implicit, so that Lean will <em>not</em> let you provide them explicitly (unless you really insist, as we will discuss later). Rather, it expects to infer them from the context in which they are used. For example, when hypotheses <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">:</span> <span class="pre">a</span> <span class="pre">≤</span> <span class="pre">b</span></code> and <code class="docutils literal notranslate"><span class="pre">h'</span> <span class="pre">:</span> <span class="pre">b</span> <span class="pre">≤</span> <span class="pre">c</span></code> are in the context, all the following work:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span><span class="o">)</span> <span class="o">(</span><span class="n">h'</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">≤</span> <span class="n">c</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">le_refl</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">Real</span><span class="o">,</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">a</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">le_refl</span> <span class="n">a</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">a</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">le_trans</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">→</span> <span class="n">b</span> <span class="bp">≤</span> <span class="n">c</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">c</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">le_trans</span> <span class="n">h</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">≤</span> <span class="n">c</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">c</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">le_trans</span> <span class="n">h</span> <span class="n">h'</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">c</span><span class="o">)</span> </pre></div> </div> <p id="index-16">The <code class="docutils literal notranslate"><span class="pre">apply</span></code> tactic takes a proof of a general statement or implication, tries to match the conclusion with the current goal, and leaves the hypotheses, if any, as new goals. If the given proof matches the goal exactly (modulo <em>definitional</em> equality), you can use the <code class="docutils literal notranslate"><span class="pre">exact</span></code> tactic instead of <code class="docutils literal notranslate"><span class="pre">apply</span></code>. So, all of these work:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">h₀</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span><span class="o">)</span> <span class="o">(</span><span class="n">h₁</span> <span class="o">:</span> <span class="n">y</span> <span class="bp">≤</span> <span class="n">z</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">z</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">le_trans</span> <span class="bp">·</span> <span class="n">apply</span> <span class="n">h₀</span> <span class="bp">.</span> <span class="n">apply</span> <span class="n">h₁</span> <span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">h₀</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span><span class="o">)</span> <span class="o">(</span><span class="n">h₁</span> <span class="o">:</span> <span class="n">y</span> <span class="bp">≤</span> <span class="n">z</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">z</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">le_trans</span> <span class="n">h₀</span> <span class="n">apply</span> <span class="n">h₁</span> <span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">h₀</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span><span class="o">)</span> <span class="o">(</span><span class="n">h₁</span> <span class="o">:</span> <span class="n">y</span> <span class="bp">≤</span> <span class="n">z</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">z</span> <span class="o">:=</span> <span class="n">le_trans</span> <span class="n">h₀</span> <span class="n">h₁</span> <span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">le_refl</span> <span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">le_refl</span> <span class="n">x</span> </pre></div> </div> <p>In the first example, applying <code class="docutils literal notranslate"><span class="pre">le_trans</span></code> creates two goals, and we use the dots to indicate where the proof of each begins. The dots are optional, but they serve to <em>focus</em> the goal: within the block introduced by the dot, only one goal is visible, and it must be completed before the end of the block. Here we end the first block by starting a new one with another dot. We could just as well have decreased the indentation. In the fourth example and in the last example, we avoid going into tactic mode entirely: <code class="docutils literal notranslate"><span class="pre">le_trans</span> <span class="pre">h₀</span> <span class="pre">h₁</span></code> and <code class="docutils literal notranslate"><span class="pre">le_refl</span> <span class="pre">x</span></code> are the proof terms we need.</p> <p>Here are a few more library theorems:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="o">(</span><span class="n">le_refl</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span><span class="o">,</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">a</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">le_trans</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">→</span> <span class="n">b</span> <span class="bp">≤</span> <span class="n">c</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">c</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">lt_of_le_of_lt</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">→</span> <span class="n">b</span> <span class="bp"><</span> <span class="n">c</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">c</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">lt_of_lt_of_le</span> <span class="o">:</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">b</span> <span class="bp">→</span> <span class="n">b</span> <span class="bp">≤</span> <span class="n">c</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">c</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">lt_trans</span> <span class="o">:</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">b</span> <span class="bp">→</span> <span class="n">b</span> <span class="bp"><</span> <span class="n">c</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">c</span><span class="o">)</span> </pre></div> </div> <p>Use them together with <code class="docutils literal notranslate"><span class="pre">apply</span></code> and <code class="docutils literal notranslate"><span class="pre">exact</span></code> to prove the following:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h₀</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span><span class="o">)</span> <span class="o">(</span><span class="n">h₁</span> <span class="o">:</span> <span class="n">b</span> <span class="bp"><</span> <span class="n">c</span><span class="o">)</span> <span class="o">(</span><span class="n">h₂</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">≤</span> <span class="n">d</span><span class="o">)</span> <span class="o">(</span><span class="n">h₃</span> <span class="o">:</span> <span class="n">d</span> <span class="bp"><</span> <span class="n">e</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">e</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p id="index-17">In fact, Lean has a tactic that does this sort of thing automatically:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h₀</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span><span class="o">)</span> <span class="o">(</span><span class="n">h₁</span> <span class="o">:</span> <span class="n">b</span> <span class="bp"><</span> <span class="n">c</span><span class="o">)</span> <span class="o">(</span><span class="n">h₂</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">≤</span> <span class="n">d</span><span class="o">)</span> <span class="o">(</span><span class="n">h₃</span> <span class="o">:</span> <span class="n">d</span> <span class="bp"><</span> <span class="n">e</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">e</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">linarith</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">linarith</span></code> tactic is designed to handle <em>linear arithmetic</em>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">≤</span> <span class="mi">3</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="o">(</span><span class="n">h'</span> <span class="o">:</span> <span class="mi">1</span> <span class="bp">≤</span> <span class="n">a</span><span class="o">)</span> <span class="o">(</span><span class="n">h''</span> <span class="o">:</span> <span class="n">d</span> <span class="bp">=</span> <span class="mi">2</span><span class="o">)</span> <span class="o">:</span> <span class="n">d</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">≤</span> <span class="mi">5</span> <span class="bp">*</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">linarith</span> </pre></div> </div> <p>In addition to equations and inequalities in the context, <code class="docutils literal notranslate"><span class="pre">linarith</span></code> will use additional inequalities that you pass as arguments. In the next example, <code class="docutils literal notranslate"><span class="pre">exp_le_exp.mpr</span> <span class="pre">h'</span></code> is a proof of <code class="docutils literal notranslate"><span class="pre">exp</span> <span class="pre">b</span> <span class="pre">≤</span> <span class="pre">exp</span> <span class="pre">c</span></code>, as we will explain in a moment. Notice that, in Lean, we write <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span></code> to denote the application of a function <code class="docutils literal notranslate"><span class="pre">f</span></code> to the argument <code class="docutils literal notranslate"><span class="pre">x</span></code>, exactly the same way we write <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">x</span></code> to denote the result of applying a fact or theorem <code class="docutils literal notranslate"><span class="pre">h</span></code> to the argument <code class="docutils literal notranslate"><span class="pre">x</span></code>. Parentheses are only needed for compound arguments, as in <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">(x</span> <span class="pre">+</span> <span class="pre">y)</span></code>. Without the parentheses, <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span> <span class="pre">+</span> <span class="pre">y</span></code> would be parsed as <code class="docutils literal notranslate"><span class="pre">(f</span> <span class="pre">x)</span> <span class="pre">+</span> <span class="pre">y</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="mi">1</span> <span class="bp">≤</span> <span class="n">a</span><span class="o">)</span> <span class="o">(</span><span class="n">h'</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">≤</span> <span class="n">c</span><span class="o">)</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">exp</span> <span class="n">b</span> <span class="bp">≤</span> <span class="mi">3</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">exp</span> <span class="n">c</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">linarith</span> <span class="o">[</span><span class="n">exp_le_exp.mpr</span> <span class="n">h'</span><span class="o">]</span> </pre></div> </div> <p id="index-18">Here are some more theorems in the library that can be used to establish inequalities on the real numbers.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="o">(</span><span class="n">exp_le_exp</span> <span class="o">:</span> <span class="n">exp</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">exp</span> <span class="n">b</span> <span class="bp">↔</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">exp_lt_exp</span> <span class="o">:</span> <span class="n">exp</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">exp</span> <span class="n">b</span> <span class="bp">↔</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">b</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">log_le_log</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">a</span> <span class="bp">→</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">b</span> <span class="bp">→</span> <span class="o">(</span><span class="n">log</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">log</span> <span class="n">b</span> <span class="bp">↔</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span><span class="o">))</span> <span class="k">#check</span> <span class="o">(</span><span class="n">log_lt_log</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">a</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">b</span> <span class="bp">→</span> <span class="n">log</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">log</span> <span class="n">b</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_le_add</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">→</span> <span class="n">c</span> <span class="bp">≤</span> <span class="n">d</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">c</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">d</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_le_add_left</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">→</span> <span class="bp">∀</span> <span class="n">c</span><span class="o">,</span> <span class="n">c</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">c</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_le_add_right</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">→</span> <span class="bp">∀</span> <span class="n">c</span><span class="o">,</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">c</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">c</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_lt_add_of_le_of_lt</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">→</span> <span class="n">c</span> <span class="bp"><</span> <span class="n">d</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">c</span> <span class="bp"><</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">d</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_lt_add_of_lt_of_le</span> <span class="o">:</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">b</span> <span class="bp">→</span> <span class="n">c</span> <span class="bp">≤</span> <span class="n">d</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">c</span> <span class="bp"><</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">d</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_lt_add_left</span> <span class="o">:</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">b</span> <span class="bp">→</span> <span class="bp">∀</span> <span class="n">c</span><span class="o">,</span> <span class="n">c</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">c</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_lt_add_right</span> <span class="o">:</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">b</span> <span class="bp">→</span> <span class="bp">∀</span> <span class="n">c</span><span class="o">,</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">c</span> <span class="bp"><</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">c</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_nonneg</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">a</span> <span class="bp">→</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">→</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_pos</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">a</span> <span class="bp">→</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">b</span> <span class="bp">→</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_pos_of_pos_of_nonneg</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">a</span> <span class="bp">→</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">→</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">exp_pos</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span><span class="o">,</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">exp</span> <span class="n">a</span><span class="o">)</span> <span class="k">#check</span> <span class="bp">@</span><span class="n">add_le_add_left</span> </pre></div> </div> <p>Some of the theorems, <code class="docutils literal notranslate"><span class="pre">exp_le_exp</span></code>, <code class="docutils literal notranslate"><span class="pre">exp_lt_exp</span></code>, and <code class="docutils literal notranslate"><span class="pre">log_le_log</span></code> use a <em>bi-implication</em>, which represents the phrase “if and only if.” (You can type it in VS Code with <code class="docutils literal notranslate"><span class="pre">\lr</span></code> of <code class="docutils literal notranslate"><span class="pre">\iff</span></code>). We will discuss this connective in greater detail in the next chapter. Such a theorem can be used with <code class="docutils literal notranslate"><span class="pre">rw</span></code> to rewrite a goal to an equivalent one:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span><span class="o">)</span> <span class="o">:</span> <span class="n">exp</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">exp</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">exp_le_exp</span><span class="o">]</span> <span class="n">exact</span> <span class="n">h</span> </pre></div> </div> <p>In this section, however, we will use the fact that if <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">:</span> <span class="pre">A</span> <span class="pre">↔</span> <span class="pre">B</span></code> is such an equivalence, then <code class="docutils literal notranslate"><span class="pre">h.mp</span></code> establishes the forward direction, <code class="docutils literal notranslate"><span class="pre">A</span> <span class="pre">→</span> <span class="pre">B</span></code>, and <code class="docutils literal notranslate"><span class="pre">h.mpr</span></code> establishes the reverse direction, <code class="docutils literal notranslate"><span class="pre">B</span> <span class="pre">→</span> <span class="pre">A</span></code>. Here, <code class="docutils literal notranslate"><span class="pre">mp</span></code> stands for “modus ponens” and <code class="docutils literal notranslate"><span class="pre">mpr</span></code> stands for “modus ponens reverse.” You can also use <code class="docutils literal notranslate"><span class="pre">h.1</span></code> and <code class="docutils literal notranslate"><span class="pre">h.2</span></code> for <code class="docutils literal notranslate"><span class="pre">h.mp</span></code> and <code class="docutils literal notranslate"><span class="pre">h.mpr</span></code>, respectively, if you prefer. Thus the following proof works:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h₀</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span><span class="o">)</span> <span class="o">(</span><span class="n">h₁</span> <span class="o">:</span> <span class="n">c</span> <span class="bp"><</span> <span class="n">d</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">exp</span> <span class="n">c</span> <span class="bp">+</span> <span class="n">e</span> <span class="bp"><</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">exp</span> <span class="n">d</span> <span class="bp">+</span> <span class="n">e</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">add_lt_add_of_lt_of_le</span> <span class="bp">·</span> <span class="n">apply</span> <span class="n">add_lt_add_of_le_of_lt</span> <span class="n">h₀</span> <span class="n">apply</span> <span class="n">exp_lt_exp.mpr</span> <span class="n">h₁</span> <span class="n">apply</span> <span class="n">le_refl</span> </pre></div> </div> <p>The first line, <code class="docutils literal notranslate"><span class="pre">apply</span> <span class="pre">add_lt_add_of_lt_of_le</span></code>, creates two goals, and once again we use a dot to separate the proof of the first from the proof of the second.</p> <p id="index-19">Try the following examples on your own. The example in the middle shows you that the <code class="docutils literal notranslate"><span class="pre">norm_num</span></code> tactic can be used to solve concrete numeric goals.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h₀</span> <span class="o">:</span> <span class="n">d</span> <span class="bp">≤</span> <span class="n">e</span><span class="o">)</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">+</span> <span class="n">exp</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">d</span><span class="o">)</span> <span class="bp">≤</span> <span class="n">c</span> <span class="bp">+</span> <span class="n">exp</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">e</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="mi">0</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="bp"><</span> <span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">norm_num</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span><span class="o">)</span> <span class="o">:</span> <span class="n">log</span> <span class="o">(</span><span class="mi">1</span> <span class="bp">+</span> <span class="n">exp</span> <span class="n">a</span><span class="o">)</span> <span class="bp">≤</span> <span class="n">log</span> <span class="o">(</span><span class="mi">1</span> <span class="bp">+</span> <span class="n">exp</span> <span class="n">b</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="k">have</span> <span class="n">h₀</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="mi">1</span> <span class="bp">+</span> <span class="n">exp</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="n">h₁</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="mi">1</span> <span class="bp">+</span> <span class="n">exp</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="n">apply</span> <span class="o">(</span><span class="n">log_le_log</span> <span class="n">h₀</span> <span class="n">h₁</span><span class="o">)</span><span class="bp">.</span><span class="n">mpr</span> <span class="gr">sorry</span> </pre></div> </div> <p>From these examples, it should be clear that being able to find the library theorems you need constitutes an important part of formalization. There are a number of strategies you can use:</p> <ul class="simple"> <li><p>You can browse mathlib in its <a class="reference external" href="https://github.com/leanprover-community/mathlib">GitHub repository</a>.</p></li> <li><p>You can use the API documentation on the mathlib <a class="reference external" href="https://leanprover-community.github.io/mathlib_docs/">web pages</a>.</p></li> <li><p>You can rely on mathlib naming conventions and tab completion in the editor to guess a theorem name. In Lean, a theorem named <code class="docutils literal notranslate"><span class="pre">A_of_B_of_C</span></code> establishes something of the form <code class="docutils literal notranslate"><span class="pre">A</span></code> from hypotheses of the form <code class="docutils literal notranslate"><span class="pre">B</span></code> and <code class="docutils literal notranslate"><span class="pre">C</span></code>, where <code class="docutils literal notranslate"><span class="pre">A</span></code>, <code class="docutils literal notranslate"><span class="pre">B</span></code>, and <code class="docutils literal notranslate"><span class="pre">C</span></code> approximate the way we might read the goals out loud. So a theorem establishing something like <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">+</span> <span class="pre">y</span> <span class="pre">≤</span> <span class="pre">...</span></code> will probably start with <code class="docutils literal notranslate"><span class="pre">add_le</span></code>. Typing <code class="docutils literal notranslate"><span class="pre">add_le</span></code> and hitting tab will give you some helpful choices.</p></li> <li><p>If you right-click on an existing theorem name in VS Code, the editor will show a menu with the option to jump to the file where the theorem is defined, and you can find similar theorems nearby.</p></li> <li><p>You can use the <code class="docutils literal notranslate"><span class="pre">library_search</span></code> tactic, which tries to find the relevant theorem in the library.</p></li> </ul> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">a</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="c1">-- library_search</span> <span class="n">exact</span> <span class="n">sq_nonneg</span> <span class="n">a</span> </pre></div> </div> <p>To try out <code class="docutils literal notranslate"><span class="pre">library_search</span></code> in this example, delete the <code class="docutils literal notranslate"><span class="pre">exact</span></code> command and uncomment the previous line. Using these tricks, see if you can find what you need to do the next example:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span><span class="o">)</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">-</span> <span class="n">exp</span> <span class="n">b</span> <span class="bp">≤</span> <span class="n">c</span> <span class="bp">-</span> <span class="n">exp</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Using the same tricks, confirm that <code class="docutils literal notranslate"><span class="pre">linarith</span></code> instead of <code class="docutils literal notranslate"><span class="pre">library_search</span></code> can also finish the job.</p> <p>Here is another example of an inequality:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">≤</span> <span class="n">a</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="k">have</span> <span class="n">h</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">a</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">-</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">^</span> <span class="mi">2</span> <span class="k">calc</span> <span class="n">a</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">-</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">=</span> <span class="o">(</span><span class="n">a</span> <span class="bp">-</span> <span class="n">b</span><span class="o">)</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ring</span> <span class="n">_</span> <span class="bp">≥</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">pow_two_nonneg</span> <span class="k">calc</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">=</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">+</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ring</span> <span class="n">_</span> <span class="bp">≤</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">+</span> <span class="o">(</span><span class="n">a</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">-</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">^</span> <span class="mi">2</span><span class="o">)</span> <span class="o">:=</span> <span class="n">add_le_add</span> <span class="o">(</span><span class="n">le_refl</span> <span class="n">_</span><span class="o">)</span> <span class="n">h</span> <span class="n">_</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ring</span> </pre></div> </div> <p>Mathlib tends to put spaces around binary operations like <code class="docutils literal notranslate"><span class="pre">*</span></code> and <code class="docutils literal notranslate"><span class="pre">^</span></code>, but in this example, the more compressed format increases readability. There are a number of things worth noticing. First, an expression <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">≥</span> <span class="pre">t</span></code> is definitionally equivalent to <code class="docutils literal notranslate"><span class="pre">t</span> <span class="pre">≤</span> <span class="pre">s</span></code>. In principle, this means one should be able to use them interchangeably. But some of Lean’s automation does not recognize the equivalence, so mathlib tends to favor <code class="docutils literal notranslate"><span class="pre">≤</span></code> over <code class="docutils literal notranslate"><span class="pre">≥</span></code>. Second, we have used the <code class="docutils literal notranslate"><span class="pre">ring</span></code> tactic extensively. It is a real timesaver! Finally, notice that in the second line of the second <code class="docutils literal notranslate"><span class="pre">calc</span></code> proof, instead of writing <code class="docutils literal notranslate"><span class="pre">by</span> <span class="pre">exact</span> <span class="pre">add_le_add</span> <span class="pre">(le_refl</span> <span class="pre">_)</span> <span class="pre">h</span></code>, we can simply write the proof term <code class="docutils literal notranslate"><span class="pre">add_le_add</span> <span class="pre">(le_refl</span> <span class="pre">_)</span> <span class="pre">h</span></code>.</p> <p>In fact, the only cleverness in the proof above is figuring out the hypothesis <code class="docutils literal notranslate"><span class="pre">h</span></code>. Once we have it, the second calculation involves only linear arithmetic, and <code class="docutils literal notranslate"><span class="pre">linarith</span></code> can handle it:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">≤</span> <span class="n">a</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="k">have</span> <span class="n">h</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">a</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">-</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">^</span> <span class="mi">2</span> <span class="k">calc</span> <span class="n">a</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">-</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">=</span> <span class="o">(</span><span class="n">a</span> <span class="bp">-</span> <span class="n">b</span><span class="o">)</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ring</span> <span class="n">_</span> <span class="bp">≥</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">pow_two_nonneg</span> <span class="n">linarith</span> </pre></div> </div> <p>How nice! We challenge you to use these ideas to prove the following theorem. You can use the theorem <code class="docutils literal notranslate"><span class="pre">abs_le'.mpr</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">abs</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="bp">≤</span> <span class="o">(</span><span class="n">a</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">^</span> <span class="mi">2</span><span class="o">)</span> <span class="bp">/</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">#check</span> <span class="n">abs_le'.mpr</span> </pre></div> </div> <p>If you managed to solve this, congratulations! You are well on your way to becoming a master formalizer.</p> </section> <section id="more-on-order-and-divisibility"> <span id="id4"></span><h2><span class="section-number">2.4. </span>More on Order and Divisibility<a class="headerlink" href="#more-on-order-and-divisibility" title="Permalink to this heading"></a></h2> <p id="index-20">The <code class="docutils literal notranslate"><span class="pre">min</span></code> function on the real numbers is uniquely characterized by the following three facts:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="o">(</span><span class="n">min_le_left</span> <span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">min</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">≤</span> <span class="n">a</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">min_le_right</span> <span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">min</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">≤</span> <span class="n">b</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">le_min</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">≤</span> <span class="n">a</span> <span class="bp">→</span> <span class="n">c</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">→</span> <span class="n">c</span> <span class="bp">≤</span> <span class="n">min</span> <span class="n">a</span> <span class="n">b</span><span class="o">)</span> </pre></div> </div> <p>Can you guess the names of the theorems that characterize <code class="docutils literal notranslate"><span class="pre">max</span></code> in a similar way?</p> <p>Notice that we have to apply <code class="docutils literal notranslate"><span class="pre">min</span></code> to a pair of arguments <code class="docutils literal notranslate"><span class="pre">a</span></code> and <code class="docutils literal notranslate"><span class="pre">b</span></code> by writing <code class="docutils literal notranslate"><span class="pre">min</span> <span class="pre">a</span> <span class="pre">b</span></code> rather than <code class="docutils literal notranslate"><span class="pre">min</span> <span class="pre">(a,</span> <span class="pre">b)</span></code>. Formally, <code class="docutils literal notranslate"><span class="pre">min</span></code> is a function of type <code class="docutils literal notranslate"><span class="pre">ℝ</span> <span class="pre">→</span> <span class="pre">ℝ</span> <span class="pre">→</span> <span class="pre">ℝ</span></code>. When we write a type like this with multiple arrows, the convention is that the implicit parentheses associate to the right, so the type is interpreted as <code class="docutils literal notranslate"><span class="pre">ℝ</span> <span class="pre">→</span> <span class="pre">(ℝ</span> <span class="pre">→</span> <span class="pre">ℝ)</span></code>. The net effect is that if <code class="docutils literal notranslate"><span class="pre">a</span></code> and <code class="docutils literal notranslate"><span class="pre">b</span></code> have type <code class="docutils literal notranslate"><span class="pre">ℝ</span></code> then <code class="docutils literal notranslate"><span class="pre">min</span> <span class="pre">a</span></code> has type <code class="docutils literal notranslate"><span class="pre">ℝ</span> <span class="pre">→</span> <span class="pre">ℝ</span></code> and <code class="docutils literal notranslate"><span class="pre">min</span> <span class="pre">a</span> <span class="pre">b</span></code> has type <code class="docutils literal notranslate"><span class="pre">ℝ</span></code>, so <code class="docutils literal notranslate"><span class="pre">min</span></code> acts like a function of two arguments, as we expect. Handling multiple arguments in this way is known as <em>currying</em>, after the logician Haskell Curry.</p> <p>The order of operations in Lean can also take some getting used to. Function application binds tighter than infix operations, so the expression <code class="docutils literal notranslate"><span class="pre">min</span> <span class="pre">a</span> <span class="pre">b</span> <span class="pre">+</span> <span class="pre">c</span></code> is interpreted as <code class="docutils literal notranslate"><span class="pre">(min</span> <span class="pre">a</span> <span class="pre">b)</span> <span class="pre">+</span> <span class="pre">c</span></code>. With time, these conventions will become second nature.</p> <p>Using the theorem <code class="docutils literal notranslate"><span class="pre">le_antisymm</span></code>, we can show that two real numbers are equal if each is less than or equal to the other. Using this and the facts above, we can show that <code class="docutils literal notranslate"><span class="pre">min</span></code> is commutative:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">min</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">min</span> <span class="n">b</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">le_antisymm</span> <span class="bp">·</span> <span class="k">show</span> <span class="n">min</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">≤</span> <span class="n">min</span> <span class="n">b</span> <span class="n">a</span> <span class="n">apply</span> <span class="n">le_min</span> <span class="bp">·</span> <span class="n">apply</span> <span class="n">min_le_right</span> <span class="n">apply</span> <span class="n">min_le_left</span> <span class="bp">·</span> <span class="k">show</span> <span class="n">min</span> <span class="n">b</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">min</span> <span class="n">a</span> <span class="n">b</span> <span class="n">apply</span> <span class="n">le_min</span> <span class="bp">·</span> <span class="n">apply</span> <span class="n">min_le_right</span> <span class="n">apply</span> <span class="n">min_le_left</span> </pre></div> </div> <p id="index-21">Here we have used dots to separate proofs of different goals. Our usage is inconsistent: at the outer level, we use dots and indentation for both goals, whereas for the nested proofs, we use dots only until a single goal remains. Both conventions are reasonable and useful. We also use the <code class="docutils literal notranslate"><span class="pre">show</span></code> tactic to structure the proof and indicate what is being proved in each block. The proof still works without the <code class="docutils literal notranslate"><span class="pre">show</span></code> commands, but using them makes the proof easier to read and maintain.</p> <p>It may bother you that the the proof is repetitive. To foreshadow skills you will learn later on, we note that one way to avoid the repetition is to state a local lemma and then use it:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">min</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">min</span> <span class="n">b</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="k">have</span> <span class="n">h</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">,</span> <span class="n">min</span> <span class="n">x</span> <span class="n">y</span> <span class="bp">≤</span> <span class="n">min</span> <span class="n">y</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">y</span> <span class="n">apply</span> <span class="n">le_min</span> <span class="n">apply</span> <span class="n">min_le_right</span> <span class="n">apply</span> <span class="n">min_le_left</span> <span class="n">apply</span> <span class="n">le_antisymm</span> <span class="n">apply</span> <span class="n">h</span> <span class="n">apply</span> <span class="n">h</span> </pre></div> </div> <p>We will say more about the universal quantifier in <a class="reference internal" href="C03_Logic.html#implication-and-the-universal-quantifier"><span class="std std-numref">Section 3.1</span></a>, but suffice it to say here that the hypothesis <code class="docutils literal notranslate"><span class="pre">h</span></code> says that the desired inequality holds for any <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code>, and the <code class="docutils literal notranslate"><span class="pre">intro</span></code> tactic introduces an arbitrary <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code> to establish the conclusion. The first <code class="docutils literal notranslate"><span class="pre">apply</span></code> after <code class="docutils literal notranslate"><span class="pre">le_antisymm</span></code> implicitly uses <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">a</span> <span class="pre">b</span></code>, whereas the second one uses <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">b</span> <span class="pre">a</span></code>.</p> <p id="index-22">Another solution is to use the <code class="docutils literal notranslate"><span class="pre">repeat</span></code> tactic, which applies a tactic (or a block) as many times as it can.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">min</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">min</span> <span class="n">b</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">le_antisymm</span> <span class="n">repeat</span> <span class="n">apply</span> <span class="n">le_min</span> <span class="n">apply</span> <span class="n">min_le_right</span> <span class="n">apply</span> <span class="n">min_le_left</span> </pre></div> </div> <p>In any case, whether or not you use these tricks, we encourage you to prove the following:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">max</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">max</span> <span class="n">b</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">min</span> <span class="o">(</span><span class="n">min</span> <span class="n">a</span> <span class="n">b</span><span class="o">)</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">min</span> <span class="n">a</span> <span class="o">(</span><span class="n">min</span> <span class="n">b</span> <span class="n">c</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Of course, you are welcome to prove the associativity of <code class="docutils literal notranslate"><span class="pre">max</span></code> as well.</p> <p>It is an interesting fact that <code class="docutils literal notranslate"><span class="pre">min</span></code> distributes over <code class="docutils literal notranslate"><span class="pre">max</span></code> the way that multiplication distributes over addition, and vice-versa. In other words, on the real numbers, we have the identity <code class="docutils literal notranslate"><span class="pre">min</span> <span class="pre">a</span> <span class="pre">(max</span> <span class="pre">b</span> <span class="pre">c)</span> <span class="pre">≤</span> <span class="pre">max</span> <span class="pre">(min</span> <span class="pre">a</span> <span class="pre">b)</span> <span class="pre">(min</span> <span class="pre">a</span> <span class="pre">c)</span></code> as well as the corresponding version with <code class="docutils literal notranslate"><span class="pre">max</span></code> and <code class="docutils literal notranslate"><span class="pre">min</span></code> switched. But in the next section we will see that this does <em>not</em> follow from the transitivity and reflexivity of <code class="docutils literal notranslate"><span class="pre">≤</span></code> and the characterizing properties of <code class="docutils literal notranslate"><span class="pre">min</span></code> and <code class="docutils literal notranslate"><span class="pre">max</span></code> enumerated above. We need to use the fact that <code class="docutils literal notranslate"><span class="pre">≤</span></code> on the real numbers is a <em>total order</em>, which is to say, it satisfies <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">x</span> <span class="pre">y,</span> <span class="pre">x</span> <span class="pre">≤</span> <span class="pre">y</span> <span class="pre">∨</span> <span class="pre">y</span> <span class="pre">≤</span> <span class="pre">x</span></code>. Here the disjunction symbol, <code class="docutils literal notranslate"><span class="pre">∨</span></code>, represents “or”. In the first case, we have <code class="docutils literal notranslate"><span class="pre">min</span> <span class="pre">x</span> <span class="pre">y</span> <span class="pre">=</span> <span class="pre">x</span></code>, and in the second case, we have <code class="docutils literal notranslate"><span class="pre">min</span> <span class="pre">x</span> <span class="pre">y</span> <span class="pre">=</span> <span class="pre">y</span></code>. We will learn how to reason by cases in <a class="reference internal" href="C03_Logic.html#disjunction"><span class="std std-numref">Section 3.5</span></a>, but for now we will stick to examples that don’t require the case split.</p> <p>Here is one such example:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">aux</span> <span class="o">:</span> <span class="n">min</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">c</span> <span class="bp">≤</span> <span class="n">min</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">c</span><span class="o">)</span> <span class="o">(</span><span class="n">b</span> <span class="bp">+</span> <span class="n">c</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">min</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">min</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">c</span><span class="o">)</span> <span class="o">(</span><span class="n">b</span> <span class="bp">+</span> <span class="n">c</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>It is clear that <code class="docutils literal notranslate"><span class="pre">aux</span></code> provides one of the two inequalities needed to prove the equality, but applying it to suitable values yields the other direction as well. As a hint, you can use the theorem <code class="docutils literal notranslate"><span class="pre">add_neg_cancel_right</span></code> and the <code class="docutils literal notranslate"><span class="pre">linarith</span></code> tactic.</p> <p id="index-23">Lean’s naming convention is made manifest in the library’s name for the triangle inequality:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="o">(</span><span class="n">abs_add</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">,</span> <span class="n">abs</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">≤</span> <span class="n">abs</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">abs</span> <span class="n">b</span><span class="o">)</span> </pre></div> </div> <p>Use it to prove the following variant:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">abs</span> <span class="n">a</span> <span class="bp">-</span> <span class="n">abs</span> <span class="n">b</span> <span class="bp">≤</span> <span class="n">abs</span> <span class="o">(</span><span class="n">a</span> <span class="bp">-</span> <span class="n">b</span><span class="o">)</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>See if you can do this in three lines or less. You can use the theorem <code class="docutils literal notranslate"><span class="pre">sub_add_cancel</span></code>.</p> <p id="index-24">Another important relation that we will make use of in the sections to come is the divisibility relation on the natural numbers, <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">∣</span> <span class="pre">y</span></code>. Be careful: the divisibility symbol is <em>not</em> the ordinary bar on your keyboard. Rather, it is a unicode character obtained by typing <code class="docutils literal notranslate"><span class="pre">\|</span></code> in VS Code. By convention, mathlib uses <code class="docutils literal notranslate"><span class="pre">dvd</span></code> to refer to it in theorem names.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h₀</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∣</span> <span class="n">y</span><span class="o">)</span> <span class="o">(</span><span class="n">h₁</span> <span class="o">:</span> <span class="n">y</span> <span class="bp">∣</span> <span class="n">z</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∣</span> <span class="n">z</span> <span class="o">:=</span> <span class="n">dvd_trans</span> <span class="n">h₀</span> <span class="n">h₁</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∣</span> <span class="n">y</span> <span class="bp">*</span> <span class="n">x</span> <span class="bp">*</span> <span class="n">z</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">dvd_mul_of_dvd_left</span> <span class="n">apply</span> <span class="n">dvd_mul_left</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∣</span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">dvd_mul_left</span> </pre></div> </div> <p>In the last example, the exponent is a natural number, and applying <code class="docutils literal notranslate"><span class="pre">dvd_mul_left</span></code> forces Lean to expand the definition of <code class="docutils literal notranslate"><span class="pre">x^2</span></code> to <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">*</span> <span class="pre">x^1</span></code>. See if you can guess the names of the theorems you need to prove the following:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∣</span> <span class="n">w</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∣</span> <span class="n">y</span> <span class="bp">*</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">z</span><span class="o">)</span> <span class="bp">+</span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="n">w</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p id="index-25">With respect to divisibility, the <em>greatest common divisor</em>, <code class="docutils literal notranslate"><span class="pre">gcd</span></code>, and least common multiple, <code class="docutils literal notranslate"><span class="pre">lcm</span></code>, are analogous to <code class="docutils literal notranslate"><span class="pre">min</span></code> and <code class="docutils literal notranslate"><span class="pre">max</span></code>. Since every number divides <code class="docutils literal notranslate"><span class="pre">0</span></code>, <code class="docutils literal notranslate"><span class="pre">0</span></code> is really the greatest element with respect to divisibility:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">(</span><span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="kn">open</span> <span class="n">Nat</span> <span class="k">#check</span> <span class="o">(</span><span class="n">gcd_zero_right</span> <span class="n">n</span> <span class="o">:</span> <span class="n">gcd</span> <span class="n">n</span> <span class="mi">0</span> <span class="bp">=</span> <span class="n">n</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">gcd_zero_left</span> <span class="n">n</span> <span class="o">:</span> <span class="n">gcd</span> <span class="mi">0</span> <span class="n">n</span> <span class="bp">=</span> <span class="n">n</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">lcm_zero_right</span> <span class="n">n</span> <span class="o">:</span> <span class="n">lcm</span> <span class="n">n</span> <span class="mi">0</span> <span class="bp">=</span> <span class="mi">0</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">lcm_zero_left</span> <span class="n">n</span> <span class="o">:</span> <span class="n">lcm</span> <span class="mi">0</span> <span class="n">n</span> <span class="bp">=</span> <span class="mi">0</span><span class="o">)</span> </pre></div> </div> <p>The functions <code class="docutils literal notranslate"><span class="pre">gcd</span></code> and <code class="docutils literal notranslate"><span class="pre">lcm</span></code> for natural numbers are in the <code class="docutils literal notranslate"><span class="pre">Nat</span></code> namespace, which means that the full identifiers are <code class="docutils literal notranslate"><span class="pre">Nat.gcd</span></code> and <code class="docutils literal notranslate"><span class="pre">Nat.lcm</span></code>. Similarly, the names of the theorems listed are prefixed by <code class="docutils literal notranslate"><span class="pre">Nat</span></code>. The command <code class="docutils literal notranslate"><span class="pre">open</span> <span class="pre">Nat</span></code> opens the namespace, allowing us to use the shorter names.</p> <p>See if you can guess the names of the theorems you will need to prove the following:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">gcd</span> <span class="n">m</span> <span class="n">n</span> <span class="bp">=</span> <span class="n">gcd</span> <span class="n">n</span> <span class="n">m</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Hint: you can use <code class="docutils literal notranslate"><span class="pre">dvd_antisymm</span></code>, but if you do, Lean will complain that the expression is ambiguous between the generic theorem and the version <code class="docutils literal notranslate"><span class="pre">Nat.dvd_antisymm</span></code>, the one specifically for the natural numbers. You can use <code class="docutils literal notranslate"><span class="pre">_root_.dvd_antisymm</span></code> to specify the generic one; either one will work.</p> </section> <section id="proving-facts-about-algebraic-structures"> <span id="id5"></span><h2><span class="section-number">2.5. </span>Proving Facts about Algebraic Structures<a class="headerlink" href="#proving-facts-about-algebraic-structures" title="Permalink to this heading"></a></h2> <p id="index-26">In <a class="reference internal" href="#proving-identities-in-algebraic-structures"><span class="std std-numref">Section 2.2</span></a>, we saw that many common identities governing the real numbers hold in more general classes of algebraic structures, such as commutative rings. We can use any axioms we want to describe an algebraic structure, not just equations. For example, a <em>partial order</em> consists of a set with a binary relation that is reflexive and transitive, like <code class="docutils literal notranslate"><span class="pre">≤</span></code> on the real numbers. Lean knows about partial orders:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">PartialOrder</span> <span class="n">α</span><span class="o">]</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="k">#check</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="k">#check</span> <span class="o">(</span><span class="n">le_refl</span> <span class="n">x</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">x</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">le_trans</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">→</span> <span class="n">y</span> <span class="bp">≤</span> <span class="n">z</span> <span class="bp">→</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">z</span><span class="o">)</span> </pre></div> </div> <p>Here we are adopting the mathlib convention of using letters like <code class="docutils literal notranslate"><span class="pre">α</span></code>, <code class="docutils literal notranslate"><span class="pre">β</span></code>, and <code class="docutils literal notranslate"><span class="pre">γ</span></code> (entered as <code class="docutils literal notranslate"><span class="pre">\a</span></code>, <code class="docutils literal notranslate"><span class="pre">\b</span></code>, and <code class="docutils literal notranslate"><span class="pre">\g</span></code>) for arbitrary types. The library often uses letters like <code class="docutils literal notranslate"><span class="pre">R</span></code> and <code class="docutils literal notranslate"><span class="pre">G</span></code> for the carries of algebraic structures like rings and groups, respectively, but in general Greek letters are used for types, especially when there is little or no structure associated with them.</p> <p>Associated to any partial order, <code class="docutils literal notranslate"><span class="pre">≤</span></code>, there is also a <em>strict partial order</em>, <code class="docutils literal notranslate"><span class="pre"><</span></code>, which acts somewhat like <code class="docutils literal notranslate"><span class="pre"><</span></code> on the real numbers. Saying that <code class="docutils literal notranslate"><span class="pre">x</span></code> is less than <code class="docutils literal notranslate"><span class="pre">y</span></code> in this order is equivalent to saying that it is less-than-or-equal to <code class="docutils literal notranslate"><span class="pre">y</span></code> and not equal to <code class="docutils literal notranslate"><span class="pre">y</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">y</span> <span class="k">#check</span> <span class="o">(</span><span class="n">lt_irrefl</span> <span class="n">x</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">x</span> <span class="bp"><</span> <span class="n">x</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">lt_trans</span> <span class="o">:</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">y</span> <span class="bp">→</span> <span class="n">y</span> <span class="bp"><</span> <span class="n">z</span> <span class="bp">→</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">z</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">lt_of_le_of_lt</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">→</span> <span class="n">y</span> <span class="bp"><</span> <span class="n">z</span> <span class="bp">→</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">z</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">lt_of_lt_of_le</span> <span class="o">:</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">y</span> <span class="bp">→</span> <span class="n">y</span> <span class="bp">≤</span> <span class="n">z</span> <span class="bp">→</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">z</span><span class="o">)</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">y</span> <span class="bp">↔</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp">≠</span> <span class="n">y</span> <span class="o">:=</span> <span class="n">lt_iff_le_and_ne</span> </pre></div> </div> <p>In this example, the symbol <code class="docutils literal notranslate"><span class="pre">∧</span></code> stands for “and,” the symbol <code class="docutils literal notranslate"><span class="pre">¬</span></code> stands for “not,” and <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">≠</span> <span class="pre">y</span></code> abbreviates <code class="docutils literal notranslate"><span class="pre">¬</span> <span class="pre">(x</span> <span class="pre">=</span> <span class="pre">y)</span></code>. In <a class="reference internal" href="C03_Logic.html#logic"><span class="std std-numref">Chapter 3</span></a>, you will learn how to use these logical connectives to <em>prove</em> that <code class="docutils literal notranslate"><span class="pre"><</span></code> has the properties indicated.</p> <p id="index-27">A <em>lattice</em> is a structure that extends a partial order with operations <code class="docutils literal notranslate"><span class="pre">⊓</span></code> and <code class="docutils literal notranslate"><span class="pre">⊔</span></code> that are analogous to <code class="docutils literal notranslate"><span class="pre">min</span></code> and <code class="docutils literal notranslate"><span class="pre">max</span></code> on the real numbers:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">Lattice</span> <span class="n">α</span><span class="o">]</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="k">#check</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="n">y</span> <span class="k">#check</span> <span class="o">(</span><span class="n">inf_le_left</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="n">y</span> <span class="bp">≤</span> <span class="n">x</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">inf_le_right</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="n">y</span> <span class="bp">≤</span> <span class="n">y</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">le_inf</span> <span class="o">:</span> <span class="n">z</span> <span class="bp">≤</span> <span class="n">x</span> <span class="bp">→</span> <span class="n">z</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">→</span> <span class="n">z</span> <span class="bp">≤</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="n">y</span><span class="o">)</span> <span class="k">#check</span> <span class="n">x</span> <span class="bp">⊔</span> <span class="n">y</span> <span class="k">#check</span> <span class="o">(</span><span class="n">le_sup_left</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">x</span> <span class="bp">⊔</span> <span class="n">y</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">le_sup_right</span> <span class="o">:</span> <span class="n">y</span> <span class="bp">≤</span> <span class="n">x</span> <span class="bp">⊔</span> <span class="n">y</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">sup_le</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">z</span> <span class="bp">→</span> <span class="n">y</span> <span class="bp">≤</span> <span class="n">z</span> <span class="bp">→</span> <span class="n">x</span> <span class="bp">⊔</span> <span class="n">y</span> <span class="bp">≤</span> <span class="n">z</span><span class="o">)</span> </pre></div> </div> <p>The characterizations of <code class="docutils literal notranslate"><span class="pre">⊓</span></code> and <code class="docutils literal notranslate"><span class="pre">⊔</span></code> justify calling them the <em>greatest lower bound</em> and <em>least upper bound</em>, respectively. You can type them in VS code using <code class="docutils literal notranslate"><span class="pre">\glb</span></code> and <code class="docutils literal notranslate"><span class="pre">\lub</span></code>. The symbols are also often called then <em>infimum</em> and the <em>supremum</em>, and mathlib refers to them as <code class="docutils literal notranslate"><span class="pre">inf</span></code> and <code class="docutils literal notranslate"><span class="pre">sup</span></code> in theorem names. To further complicate matters, they are also often called <em>meet</em> and <em>join</em>. Therefore, if you work with lattices, you have to keep the following dictionary in mind:</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">⊓</span></code> is the <em>greatest lower bound</em>, <em>infimum</em>, or <em>meet</em>.</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">⊔</span></code> is the <em>least upper bound</em>, <em>supremum</em>, or <em>join</em>.</p></li> </ul> <p>Some instances of lattices include:</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">min</span></code> and <code class="docutils literal notranslate"><span class="pre">max</span></code> on any total order, such as the integers or real numbers with <code class="docutils literal notranslate"><span class="pre">≤</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">∩</span></code> and <code class="docutils literal notranslate"><span class="pre">∪</span></code> on the collection of subsets of some domain, with the ordering <code class="docutils literal notranslate"><span class="pre">⊆</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">∧</span></code> and <code class="docutils literal notranslate"><span class="pre">∨</span></code> on boolean truth values, with ordering <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">≤</span> <span class="pre">y</span></code> if either <code class="docutils literal notranslate"><span class="pre">x</span></code> is false or <code class="docutils literal notranslate"><span class="pre">y</span></code> is true</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">gcd</span></code> and <code class="docutils literal notranslate"><span class="pre">lcm</span></code> on the natural numbers (or positive natural numbers), with the divisibility ordering, <code class="docutils literal notranslate"><span class="pre">∣</span></code></p></li> <li><p>the collection of linear subspaces of a vector space, where the greatest lower bound is given by the intersection, the least upper bound is given by the sum of the two spaces, and the ordering is inclusion</p></li> <li><p>the collection of topologies on a set (or, in Lean, a type), where the greatest lower bound of two topologies consists of the topology that is generated by their union, the least upper bound is their intersection, and the ordering is reverse inclusion</p></li> </ul> <p>You can check that, as with <code class="docutils literal notranslate"><span class="pre">min</span></code> / <code class="docutils literal notranslate"><span class="pre">max</span></code> and <code class="docutils literal notranslate"><span class="pre">gcd</span></code> / <code class="docutils literal notranslate"><span class="pre">lcm</span></code>, you can prove the commutativity and associativity of the infimum and supremum using only their characterizing axioms, together with <code class="docutils literal notranslate"><span class="pre">le_refl</span></code> and <code class="docutils literal notranslate"><span class="pre">le_trans</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="n">y</span> <span class="bp">=</span> <span class="n">y</span> <span class="bp">⊓</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="n">y</span> <span class="bp">⊓</span> <span class="n">z</span> <span class="bp">=</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="o">(</span><span class="n">y</span> <span class="bp">⊓</span> <span class="n">z</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">⊔</span> <span class="n">y</span> <span class="bp">=</span> <span class="n">y</span> <span class="bp">⊔</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">⊔</span> <span class="n">y</span> <span class="bp">⊔</span> <span class="n">z</span> <span class="bp">=</span> <span class="n">x</span> <span class="bp">⊔</span> <span class="o">(</span><span class="n">y</span> <span class="bp">⊔</span> <span class="n">z</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>You can find these theorems in the mathlib as <code class="docutils literal notranslate"><span class="pre">inf_comm</span></code>, <code class="docutils literal notranslate"><span class="pre">inf_assoc</span></code>, <code class="docutils literal notranslate"><span class="pre">sup_comm</span></code>, and <code class="docutils literal notranslate"><span class="pre">sup_assoc</span></code>, respectively.</p> <p>Another good exercise is to prove the <em>absorption laws</em> using only those axioms:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">absorb1</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="o">(</span><span class="n">x</span> <span class="bp">⊔</span> <span class="n">y</span><span class="o">)</span> <span class="bp">=</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">absorb2</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">⊔</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="n">y</span> <span class="bp">=</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>These can be found in mathlib with the names <code class="docutils literal notranslate"><span class="pre">inf_sup_self</span></code> and <code class="docutils literal notranslate"><span class="pre">sup_inf_self</span></code>.</p> <p>A lattice that satisfies the additional identities <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">⊓</span> <span class="pre">(y</span> <span class="pre">⊔</span> <span class="pre">z)</span> <span class="pre">=</span> <span class="pre">(x</span> <span class="pre">⊓</span> <span class="pre">y)</span> <span class="pre">⊔</span> <span class="pre">(x</span> <span class="pre">⊓</span> <span class="pre">z)</span></code> and <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">⊔</span> <span class="pre">(y</span> <span class="pre">⊓</span> <span class="pre">z)</span> <span class="pre">=</span> <span class="pre">(x</span> <span class="pre">⊔</span> <span class="pre">y)</span> <span class="pre">⊓</span> <span class="pre">(x</span> <span class="pre">⊔</span> <span class="pre">z)</span></code> is called a <em>distributive lattice</em>. Lean knows about these too:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">DistribLattice</span> <span class="n">α</span><span class="o">]</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">inf_sup_left</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="o">(</span><span class="n">y</span> <span class="bp">⊔</span> <span class="n">z</span><span class="o">)</span> <span class="bp">=</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="n">y</span> <span class="bp">⊔</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="n">z</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">inf_sup_right</span> <span class="o">:</span> <span class="o">(</span><span class="n">x</span> <span class="bp">⊔</span> <span class="n">y</span><span class="o">)</span> <span class="bp">⊓</span> <span class="n">z</span> <span class="bp">=</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="n">z</span> <span class="bp">⊔</span> <span class="n">y</span> <span class="bp">⊓</span> <span class="n">z</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">sup_inf_left</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">⊔</span> <span class="n">y</span> <span class="bp">⊓</span> <span class="n">z</span> <span class="bp">=</span> <span class="o">(</span><span class="n">x</span> <span class="bp">⊔</span> <span class="n">y</span><span class="o">)</span> <span class="bp">⊓</span> <span class="o">(</span><span class="n">x</span> <span class="bp">⊔</span> <span class="n">z</span><span class="o">))</span> <span class="k">#check</span> <span class="o">(</span><span class="n">sup_inf_right</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="n">y</span> <span class="bp">⊔</span> <span class="n">z</span> <span class="bp">=</span> <span class="o">(</span><span class="n">x</span> <span class="bp">⊔</span> <span class="n">z</span><span class="o">)</span> <span class="bp">⊓</span> <span class="o">(</span><span class="n">y</span> <span class="bp">⊔</span> <span class="n">z</span><span class="o">))</span> </pre></div> </div> <p>The left and right versions are easily shown to be equivalent, given the commutativity of <code class="docutils literal notranslate"><span class="pre">⊓</span></code> and <code class="docutils literal notranslate"><span class="pre">⊔</span></code>. It is a good exercise to show that not every lattice is distributive by providing an explicit description of a nondistributive lattice with finitely many elements. It is also a good exercise to show that in any lattice, either distributivity law implies the other:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">Lattice</span> <span class="n">α</span><span class="o">]</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="o">(</span><span class="n">y</span> <span class="bp">⊔</span> <span class="n">z</span><span class="o">)</span> <span class="bp">=</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="n">y</span> <span class="bp">⊔</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="n">z</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">⊔</span> <span class="n">b</span> <span class="bp">⊓</span> <span class="n">c</span> <span class="bp">=</span> <span class="o">(</span><span class="n">a</span> <span class="bp">⊔</span> <span class="n">b</span><span class="o">)</span> <span class="bp">⊓</span> <span class="o">(</span><span class="n">a</span> <span class="bp">⊔</span> <span class="n">c</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">x</span> <span class="bp">⊔</span> <span class="n">y</span> <span class="bp">⊓</span> <span class="n">z</span> <span class="bp">=</span> <span class="o">(</span><span class="n">x</span> <span class="bp">⊔</span> <span class="n">y</span><span class="o">)</span> <span class="bp">⊓</span> <span class="o">(</span><span class="n">x</span> <span class="bp">⊔</span> <span class="n">z</span><span class="o">))</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">⊓</span> <span class="o">(</span><span class="n">b</span> <span class="bp">⊔</span> <span class="n">c</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">⊓</span> <span class="n">b</span> <span class="bp">⊔</span> <span class="n">a</span> <span class="bp">⊓</span> <span class="n">c</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>It is possible to combine axiomatic structures into larger ones. For example, a <em>strict ordered ring</em> consists of a commutative ring together with a partial order on the carrier satisfying additional axioms that say that the ring operations are compatible with the order:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">R</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">StrictOrderedRing</span> <span class="n">R</span><span class="o">]</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">add_le_add_left</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">→</span> <span class="bp">∀</span> <span class="n">c</span><span class="o">,</span> <span class="n">c</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">c</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">mul_pos</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">a</span> <span class="bp">→</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">b</span> <span class="bp">→</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> </pre></div> </div> <p><a class="reference internal" href="C03_Logic.html#logic"><span class="std std-numref">Chapter 3</span></a> will provide the means to derive the following from <code class="docutils literal notranslate"><span class="pre">mul_pos</span></code> and the definition of <code class="docutils literal notranslate"><span class="pre"><</span></code>:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="o">(</span><span class="n">mul_nonneg</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">a</span> <span class="bp">→</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">→</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> </pre></div> </div> <p>It is then an extended exercise to show that many common facts used to reason about arithmetic and the ordering on the real numbers hold generically for any ordered ring. Here are a couple of examples you can try, using only properties of rings, partial orders, and the facts enumerated in the last two examples:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">→</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">-</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">-</span> <span class="n">a</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span><span class="o">)</span> <span class="o">(</span><span class="n">h'</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">c</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">c</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p id="index-28">Finally, here is one last example. A <em>metric space</em> consists of a set equipped with a notion of distance, <code class="docutils literal notranslate"><span class="pre">dist</span> <span class="pre">x</span> <span class="pre">y</span></code>, mapping any pair of elements to a real number. The distance function is assumed to satisfy the following axioms:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">X</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">X</span><span class="o">]</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="o">:</span> <span class="n">X</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">dist_self</span> <span class="n">x</span> <span class="o">:</span> <span class="n">dist</span> <span class="n">x</span> <span class="n">x</span> <span class="bp">=</span> <span class="mi">0</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">dist_comm</span> <span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">dist</span> <span class="n">x</span> <span class="n">y</span> <span class="bp">=</span> <span class="n">dist</span> <span class="n">y</span> <span class="n">x</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">dist_triangle</span> <span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="o">:</span> <span class="n">dist</span> <span class="n">x</span> <span class="n">z</span> <span class="bp">≤</span> <span class="n">dist</span> <span class="n">x</span> <span class="n">y</span> <span class="bp">+</span> <span class="n">dist</span> <span class="n">y</span> <span class="n">z</span><span class="o">)</span> </pre></div> </div> <p>Having mastered this section, you can show that it follows from these axioms that distances are always nonnegative:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">X</span><span class="o">)</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">dist</span> <span class="n">x</span> <span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>We recommend making use of the theorem <code class="docutils literal notranslate"><span class="pre">nonneg_of_mul_nonneg_left</span></code>. As you may have guessed, this theorem is called <code class="docutils literal notranslate"><span class="pre">dist_nonneg</span></code> in mathlib.</p> </section> </section> </div> </div> <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> <a href="C01_Introduction.html" class="btn btn-neutral float-left" title="1. Introduction" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> <a href="C03_Logic.html" class="btn btn-neutral float-right" title="3. Logic" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> </div> <hr/> <div role="contentinfo"> <p>© Copyright 2020, Jeremy Avigad, Kevin Buzzard, Robert Y. Lewis, Patrick Massot.</p> </div> Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. </footer> </div> </div> </section> </div> <script> jQuery(function () { SphinxRtdTheme.Navigation.enable(true); }); </script> </body> </html>
-
-
html/C03_Logic.html (new)
-
@@ -0,0 +1,1714 @@<!DOCTYPE html> <html class="writer-html5" lang="en" > <head> <meta charset="utf-8" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>3. Logic — Mathematics in Lean 0.1 documentation</title> <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> <link rel="stylesheet" href="_static/css/custom.css" type="text/css" /> <link rel="shortcut icon" href="_static/favicon.ico"/> <!--[if lt IE 9]> <script src="_static/js/html5shiv.min.js"></script> <![endif]--> <script src="_static/jquery.js"></script> <script src="_static/_sphinx_javascript_frameworks_compat.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script src="_static/doctools.js"></script> <script src="_static/sphinx_highlight.js"></script> <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> <script src="_static/js/theme.js"></script> <link rel="index" title="Index" href="genindex.html" /> <link rel="search" title="Search" href="search.html" /> <link rel="next" title="4. Sets and Functions" href="C04_Sets_and_Functions.html" /> <link rel="prev" title="2. Basics" href="C02_Basics.html" /> </head> <body class="wy-body-for-nav"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search" > <a href="index.html" class="icon icon-home"> Mathematics in Lean </a> <div role="search"> <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> <ul class="current"> <li class="toctree-l1"><a class="reference internal" href="C01_Introduction.html">1. Introduction</a></li> <li class="toctree-l1"><a class="reference internal" href="C02_Basics.html">2. Basics</a></li> <li class="toctree-l1 current"><a class="current reference internal" href="#">3. Logic</a><ul> <li class="toctree-l2"><a class="reference internal" href="#implication-and-the-universal-quantifier">3.1. Implication and the Universal Quantifier</a></li> <li class="toctree-l2"><a class="reference internal" href="#the-existential-quantifier">3.2. The Existential Quantifier</a></li> <li class="toctree-l2"><a class="reference internal" href="#negation">3.3. Negation</a></li> <li class="toctree-l2"><a class="reference internal" href="#conjunction-and-bi-implication">3.4. Conjunction and Bi-implication</a></li> <li class="toctree-l2"><a class="reference internal" href="#disjunction">3.5. Disjunction</a></li> <li class="toctree-l2"><a class="reference internal" href="#sequences-and-convergence">3.6. Sequences and Convergence</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="C04_Sets_and_Functions.html">4. Sets and Functions</a></li> <li class="toctree-l1"><a class="reference internal" href="C05_Number_Theory.html">5. Number Theory</a></li> <li class="toctree-l1"><a class="reference internal" href="C06_Structures.html">6. Structures</a></li> <li class="toctree-l1"><a class="reference internal" href="C07_Hierarchies.html">7. Hierarchies</a></li> <li class="toctree-l1"><a class="reference internal" href="C08_Topology.html">8. Topology</a></li> <li class="toctree-l1"><a class="reference internal" href="C09_Differential_Calculus.html">9. Differential Calculus</a></li> </ul> <ul> <li class="toctree-l1"><a class="reference internal" href="genindex.html">Index</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="index.html">Mathematics in Lean</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="Page navigation"> <ul class="wy-breadcrumbs"> <li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li> <li class="breadcrumb-item active"><span class="section-number">3. </span>Logic</li> <li class="wy-breadcrumbs-aside"> <a href="_sources/C03_Logic.rst.txt" rel="nofollow"> View page source</a> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <section id="logic"> <span id="id1"></span><h1><span class="section-number">3. </span>Logic<a class="headerlink" href="#logic" title="Permalink to this heading"></a></h1> <p>In the last chapter, we dealt with equations, inequalities, and basic mathematical statements like “<span class="math notranslate nohighlight">\(x\)</span> divides <span class="math notranslate nohighlight">\(y\)</span>.” Complex mathematical statements are built up from simple ones like these using logical terms like “and,” “or,” “not,” and “if … then,” “every,” and “some.” In this chapter, we show you how to work with statements that are built up in this way.</p> <section id="implication-and-the-universal-quantifier"> <span id="id2"></span><h2><span class="section-number">3.1. </span>Implication and the Universal Quantifier<a class="headerlink" href="#implication-and-the-universal-quantifier" title="Permalink to this heading"></a></h2> <p>Consider the statement after the <code class="docutils literal notranslate"><span class="pre">#check</span></code>:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="bp">∀</span> <span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">,</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">x</span> <span class="bp">→</span> <span class="n">abs</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">x</span> </pre></div> </div> <p>In words, we would say “for every real number <code class="docutils literal notranslate"><span class="pre">x</span></code>, if <code class="docutils literal notranslate"><span class="pre">0</span> <span class="pre">≤</span> <span class="pre">x</span></code> then the absolute value of <code class="docutils literal notranslate"><span class="pre">x</span></code> equals <code class="docutils literal notranslate"><span class="pre">x</span></code>”. We can also have more complicated statements like:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="bp">∀</span> <span class="n">x</span> <span class="n">y</span> <span class="n">ε</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">,</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">→</span> <span class="n">ε</span> <span class="bp">≤</span> <span class="mi">1</span> <span class="bp">→</span> <span class="n">abs</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">→</span> <span class="n">abs</span> <span class="n">y</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">→</span> <span class="n">abs</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">y</span><span class="o">)</span> <span class="bp"><</span> <span class="n">ε</span> </pre></div> </div> <p>In words, we would say “for every <code class="docutils literal notranslate"><span class="pre">x</span></code>, <code class="docutils literal notranslate"><span class="pre">y</span></code>, and <code class="docutils literal notranslate"><span class="pre">ε</span></code>, if <code class="docutils literal notranslate"><span class="pre">0</span> <span class="pre"><</span> <span class="pre">ε</span> <span class="pre">≤</span> <span class="pre">1</span></code>, the absolute value of <code class="docutils literal notranslate"><span class="pre">x</span></code> is less than <code class="docutils literal notranslate"><span class="pre">ε</span></code>, and the absolute value of <code class="docutils literal notranslate"><span class="pre">y</span></code> is less than <code class="docutils literal notranslate"><span class="pre">ε</span></code>, then the absolute value of <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">*</span> <span class="pre">y</span></code> is less than <code class="docutils literal notranslate"><span class="pre">ε</span></code>.” In Lean, in a sequence of implications there are implicit parentheses grouped to the right. So the expression above means “if <code class="docutils literal notranslate"><span class="pre">0</span> <span class="pre"><</span> <span class="pre">ε</span></code> then if <code class="docutils literal notranslate"><span class="pre">ε</span> <span class="pre">≤</span> <span class="pre">1</span></code> then if <code class="docutils literal notranslate"><span class="pre">abs</span> <span class="pre">x</span> <span class="pre"><</span> <span class="pre">ε</span></code> …” As a result, the expression says that all the assumptions together imply the conclusion.</p> <p>You have already seen that even though the universal quantifier in this statement ranges over objects and the implication arrows introduce hypotheses, Lean treats the two in very similar ways. In particular, if you have proved a theorem of that form, you can apply it to objects and hypotheses in the same way:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">my_lemma</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="n">y</span> <span class="n">ε</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">,</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">→</span> <span class="n">ε</span> <span class="bp">≤</span> <span class="mi">1</span> <span class="bp">→</span> <span class="n">abs</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">→</span> <span class="n">abs</span> <span class="n">y</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">→</span> <span class="n">abs</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">y</span><span class="o">)</span> <span class="bp"><</span> <span class="n">ε</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="kn">section</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">δ</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">h₀</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">δ</span><span class="o">)</span> <span class="o">(</span><span class="n">h₁</span> <span class="o">:</span> <span class="n">δ</span> <span class="bp">≤</span> <span class="mi">1</span><span class="o">)</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">ha</span> <span class="o">:</span> <span class="n">abs</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">δ</span><span class="o">)</span> <span class="o">(</span><span class="n">hb</span> <span class="o">:</span> <span class="n">abs</span> <span class="n">b</span> <span class="bp"><</span> <span class="n">δ</span><span class="o">)</span> <span class="k">#check</span> <span class="n">my_lemma</span> <span class="n">a</span> <span class="n">b</span> <span class="n">δ</span> <span class="k">#check</span> <span class="n">my_lemma</span> <span class="n">a</span> <span class="n">b</span> <span class="n">δ</span> <span class="n">h₀</span> <span class="n">h₁</span> <span class="k">#check</span> <span class="n">my_lemma</span> <span class="n">a</span> <span class="n">b</span> <span class="n">δ</span> <span class="n">h₀</span> <span class="n">h₁</span> <span class="n">ha</span> <span class="n">hb</span> <span class="kd">end</span> </pre></div> </div> <p>You have also already seen that it is common in Lean to use curly brackets to make quantified variables implicit when they can be inferred from subsequent hypotheses. When we do that, we can just apply a lemma to the hypotheses without mentioning the objects.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">my_lemma2</span> <span class="o">:</span> <span class="bp">∀</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="n">ε</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">},</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">→</span> <span class="n">ε</span> <span class="bp">≤</span> <span class="mi">1</span> <span class="bp">→</span> <span class="n">abs</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">→</span> <span class="n">abs</span> <span class="n">y</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">→</span> <span class="n">abs</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">y</span><span class="o">)</span> <span class="bp"><</span> <span class="n">ε</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="kn">section</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">δ</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">h₀</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">δ</span><span class="o">)</span> <span class="o">(</span><span class="n">h₁</span> <span class="o">:</span> <span class="n">δ</span> <span class="bp">≤</span> <span class="mi">1</span><span class="o">)</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">ha</span> <span class="o">:</span> <span class="n">abs</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">δ</span><span class="o">)</span> <span class="o">(</span><span class="n">hb</span> <span class="o">:</span> <span class="n">abs</span> <span class="n">b</span> <span class="bp"><</span> <span class="n">δ</span><span class="o">)</span> <span class="k">#check</span> <span class="n">my_lemma2</span> <span class="n">h₀</span> <span class="n">h₁</span> <span class="n">ha</span> <span class="n">hb</span> <span class="kd">end</span> </pre></div> </div> <p>At this stage, you also know that if you use the <code class="docutils literal notranslate"><span class="pre">apply</span></code> tactic to apply <code class="docutils literal notranslate"><span class="pre">my_lemma</span></code> to a goal of the form <code class="docutils literal notranslate"><span class="pre">abs</span> <span class="pre">(a</span> <span class="pre">*</span> <span class="pre">b)</span> <span class="pre"><</span> <span class="pre">δ</span></code>, you are left with new goals that require you to prove each of the hypotheses.</p> <p id="index-0">To prove a statement like this, use the <code class="docutils literal notranslate"><span class="pre">intro</span></code> tactic. Take a look at what it does in this example:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">my_lemma3</span> <span class="o">:</span> <span class="bp">∀</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="n">ε</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">},</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">→</span> <span class="n">ε</span> <span class="bp">≤</span> <span class="mi">1</span> <span class="bp">→</span> <span class="n">abs</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">→</span> <span class="n">abs</span> <span class="n">y</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">→</span> <span class="n">abs</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">y</span><span class="o">)</span> <span class="bp"><</span> <span class="n">ε</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">y</span> <span class="n">ε</span> <span class="n">epos</span> <span class="n">ele1</span> <span class="n">xlt</span> <span class="n">ylt</span> <span class="gr">sorry</span> </pre></div> </div> <p>We can use any names we want for the universally quantified variables; they do not have to be <code class="docutils literal notranslate"><span class="pre">x</span></code>, <code class="docutils literal notranslate"><span class="pre">y</span></code>, and <code class="docutils literal notranslate"><span class="pre">ε</span></code>. Notice that we have to introduce the variables even though they are marked implicit: making them implicit means that we leave them out when we write an expression <em>using</em> <code class="docutils literal notranslate"><span class="pre">my_lemma</span></code>, but they are still an essential part of the statement that we are proving. After the <code class="docutils literal notranslate"><span class="pre">intro</span></code> command, the goal is what it would have been at the start if we listed all the variables and hypotheses <em>before</em> the colon, as we did in the last section. In a moment, we will see why it is sometimes necessary to introduce variables and hypotheses after the proof begins.</p> <p>To help you prove the lemma, we will start you off:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">my_lemma4</span> <span class="o">:</span> <span class="bp">∀</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="n">ε</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">},</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">→</span> <span class="n">ε</span> <span class="bp">≤</span> <span class="mi">1</span> <span class="bp">→</span> <span class="n">abs</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">→</span> <span class="n">abs</span> <span class="n">y</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">→</span> <span class="n">abs</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">y</span><span class="o">)</span> <span class="bp"><</span> <span class="n">ε</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">y</span> <span class="n">ε</span> <span class="n">epos</span> <span class="n">ele1</span> <span class="n">xlt</span> <span class="n">ylt</span> <span class="k">calc</span> <span class="n">abs</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">y</span><span class="o">)</span> <span class="bp">=</span> <span class="n">abs</span> <span class="n">x</span> <span class="bp">*</span> <span class="n">abs</span> <span class="n">y</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">_</span> <span class="bp">≤</span> <span class="n">abs</span> <span class="n">x</span> <span class="bp">*</span> <span class="n">ε</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">_</span> <span class="bp"><</span> <span class="mi">1</span> <span class="bp">*</span> <span class="n">ε</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">_</span> <span class="bp">=</span> <span class="n">ε</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>Finish the proof using the theorems <code class="docutils literal notranslate"><span class="pre">abs_mul</span></code>, <code class="docutils literal notranslate"><span class="pre">mul_le_mul</span></code>, <code class="docutils literal notranslate"><span class="pre">abs_nonneg</span></code>, <code class="docutils literal notranslate"><span class="pre">mul_lt_mul_right</span></code>, and <code class="docutils literal notranslate"><span class="pre">one_mul</span></code>. Remember that you can find theorems like these using tab completion. Remember also that you can use <code class="docutils literal notranslate"><span class="pre">.mp</span></code> and <code class="docutils literal notranslate"><span class="pre">.mpr</span></code> or <code class="docutils literal notranslate"><span class="pre">.1</span></code> and <code class="docutils literal notranslate"><span class="pre">.2</span></code> to extract the two directions of an if-and-only-if statement.</p> <p>Universal quantifiers are often hidden in definitions, and Lean will unfold definitions to expose them when necessary. For example, let’s define two predicates, <code class="docutils literal notranslate"><span class="pre">FnUb</span> <span class="pre">f</span> <span class="pre">a</span></code> and <code class="docutils literal notranslate"><span class="pre">FnLb</span> <span class="pre">f</span> <span class="pre">a</span></code>, where <code class="docutils literal notranslate"><span class="pre">f</span></code> is a function from the real numbers to the real numbers and <code class="docutils literal notranslate"><span class="pre">a</span></code> is a real number. The first says that <code class="docutils literal notranslate"><span class="pre">a</span></code> is an upper bound on the values of <code class="docutils literal notranslate"><span class="pre">f</span></code>, and the second says that <code class="docutils literal notranslate"><span class="pre">a</span></code> is a lower bound on the values of <code class="docutils literal notranslate"><span class="pre">f</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">FnUb</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="kt">Prop</span> <span class="o">:=</span> <span class="bp">∀</span> <span class="n">x</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">a</span> <span class="kd">def</span> <span class="n">FnLb</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="kt">Prop</span> <span class="o">:=</span> <span class="bp">∀</span> <span class="n">x</span><span class="o">,</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">f</span> <span class="n">x</span> </pre></div> </div> <p id="index-1">In the next example, <code class="docutils literal notranslate"><span class="pre">fun</span> <span class="pre">x</span> <span class="pre">↦</span> <span class="pre">f</span> <span class="pre">x</span> <span class="pre">+</span> <span class="pre">g</span> <span class="pre">x</span></code> is a name for the function that maps <code class="docutils literal notranslate"><span class="pre">x</span></code> to <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span> <span class="pre">+</span> <span class="pre">g</span> <span class="pre">x</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">hfa</span> <span class="o">:</span> <span class="n">FnUb</span> <span class="n">f</span> <span class="n">a</span><span class="o">)</span> <span class="o">(</span><span class="n">hgb</span> <span class="o">:</span> <span class="n">FnUb</span> <span class="n">g</span> <span class="n">b</span><span class="o">)</span> <span class="o">:</span> <span class="n">FnUb</span> <span class="o">(</span><span class="k">fun</span> <span class="n">x</span> <span class="bp">↦</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">g</span> <span class="n">x</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">dsimp</span> <span class="n">apply</span> <span class="n">add_le_add</span> <span class="n">apply</span> <span class="n">hfa</span> <span class="n">apply</span> <span class="n">hgb</span> </pre></div> </div> <p id="index-2">Applying <code class="docutils literal notranslate"><span class="pre">intro</span></code> to the goal <code class="docutils literal notranslate"><span class="pre">FnUb</span> <span class="pre">(fun</span> <span class="pre">x</span> <span class="pre">↦</span> <span class="pre">f</span> <span class="pre">x</span> <span class="pre">+</span> <span class="pre">g</span> <span class="pre">x)</span> <span class="pre">(a</span> <span class="pre">+</span> <span class="pre">b)</span></code> forces Lean to unfold the definition of <code class="docutils literal notranslate"><span class="pre">FnUb</span></code> and introduce <code class="docutils literal notranslate"><span class="pre">x</span></code> for the universal quantifier. The goal is then <code class="docutils literal notranslate"><span class="pre">(fun</span> <span class="pre">(x</span> <span class="pre">:</span> <span class="pre">ℝ)</span> <span class="pre">↦</span> <span class="pre">f</span> <span class="pre">x</span> <span class="pre">+</span> <span class="pre">g</span> <span class="pre">x)</span> <span class="pre">x</span> <span class="pre">≤</span> <span class="pre">a</span> <span class="pre">+</span> <span class="pre">b</span></code>. But applying <code class="docutils literal notranslate"><span class="pre">(fun</span> <span class="pre">x</span> <span class="pre">↦</span> <span class="pre">f</span> <span class="pre">x</span> <span class="pre">+</span> <span class="pre">g</span> <span class="pre">x)</span></code> to <code class="docutils literal notranslate"><span class="pre">x</span></code> should result in <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span> <span class="pre">+</span> <span class="pre">g</span> <span class="pre">x</span></code>, and the <code class="docutils literal notranslate"><span class="pre">dsimp</span></code> command performs that simplification. (The “d” stands for “definitional.”) You can delete that command and the proof still works; Lean would have to perform that contraction anyhow to make sense of the next <code class="docutils literal notranslate"><span class="pre">apply</span></code>. The <code class="docutils literal notranslate"><span class="pre">dsimp</span></code> command simply makes the goal more readable and helps us figure out what to do next. Another option is to use the <code class="docutils literal notranslate"><span class="pre">change</span></code> tactic by writing <code class="docutils literal notranslate"><span class="pre">change</span> <span class="pre">f</span> <span class="pre">x</span> <span class="pre">+</span> <span class="pre">g</span> <span class="pre">x</span> <span class="pre">≤</span> <span class="pre">a</span> <span class="pre">+</span> <span class="pre">b</span></code>. This helps make the proof more readable, and gives you more control over how the goal is transformed.</p> <p>The rest of the proof is routine. The last two <code class="docutils literal notranslate"><span class="pre">apply</span></code> commands force Lean to unfold the definitions of <code class="docutils literal notranslate"><span class="pre">FnUb</span></code> in the hypotheses. Try carrying out similar proofs of these:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">hfa</span> <span class="o">:</span> <span class="n">FnLb</span> <span class="n">f</span> <span class="n">a</span><span class="o">)</span> <span class="o">(</span><span class="n">hgb</span> <span class="o">:</span> <span class="n">FnLb</span> <span class="n">g</span> <span class="n">b</span><span class="o">)</span> <span class="o">:</span> <span class="n">FnLb</span> <span class="o">(</span><span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">g</span> <span class="n">x</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">nnf</span> <span class="o">:</span> <span class="n">FnLb</span> <span class="n">f</span> <span class="mi">0</span><span class="o">)</span> <span class="o">(</span><span class="n">nng</span> <span class="o">:</span> <span class="n">FnLb</span> <span class="n">g</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="n">FnLb</span> <span class="o">(</span><span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="n">x</span> <span class="bp">*</span> <span class="n">g</span> <span class="n">x</span><span class="o">)</span> <span class="mi">0</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">hfa</span> <span class="o">:</span> <span class="n">FnUb</span> <span class="n">f</span> <span class="n">a</span><span class="o">)</span> <span class="o">(</span><span class="n">hfb</span> <span class="o">:</span> <span class="n">FnUb</span> <span class="n">g</span> <span class="n">b</span><span class="o">)</span> <span class="o">(</span><span class="n">nng</span> <span class="o">:</span> <span class="n">FnLb</span> <span class="n">g</span> <span class="mi">0</span><span class="o">)</span> <span class="o">(</span><span class="n">nna</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">a</span><span class="o">)</span> <span class="o">:</span> <span class="n">FnUb</span> <span class="o">(</span><span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="n">x</span> <span class="bp">*</span> <span class="n">g</span> <span class="n">x</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>Even though we have defined <code class="docutils literal notranslate"><span class="pre">FnUb</span></code> and <code class="docutils literal notranslate"><span class="pre">FnLb</span></code> for functions from the reals to the reals, you should recognize that the definitions and proofs are much more general. The definitions make sense for functions between any two types for which there is a notion of order on the codomain. Checking the type of the theorem <code class="docutils literal notranslate"><span class="pre">add_le_add</span></code> shows that it holds of any structure that is an “ordered additive commutative monoid”; the details of what that means don’t matter now, but it is worth knowing that the natural numbers, integers, rationals, and real numbers are all instances. So if we prove the theorem <code class="docutils literal notranslate"><span class="pre">fnUb_add</span></code> at that level of generality, it will apply in all these instances.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">{</span><span class="n">R</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">OrderedCancelAddCommMonoid</span> <span class="n">R</span><span class="o">]</span> <span class="k">#check</span> <span class="bp">@</span><span class="n">add_le_add</span> <span class="kd">def</span> <span class="n">FnUb'</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">R</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="o">:</span> <span class="kt">Prop</span> <span class="o">:=</span> <span class="bp">∀</span> <span class="n">x</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">a</span> <span class="kd">theorem</span> <span class="n">fnUb_add</span> <span class="o">{</span><span class="n">f</span> <span class="n">g</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">R</span><span class="o">}</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">R</span><span class="o">}</span> <span class="o">(</span><span class="n">hfa</span> <span class="o">:</span> <span class="n">FnUb'</span> <span class="n">f</span> <span class="n">a</span><span class="o">)</span> <span class="o">(</span><span class="n">hgb</span> <span class="o">:</span> <span class="n">FnUb'</span> <span class="n">g</span> <span class="n">b</span><span class="o">)</span> <span class="o">:</span> <span class="n">FnUb'</span> <span class="o">(</span><span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">g</span> <span class="n">x</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">add_le_add</span> <span class="o">(</span><span class="n">hfa</span> <span class="n">x</span><span class="o">)</span> <span class="o">(</span><span class="n">hgb</span> <span class="n">x</span><span class="o">)</span> </pre></div> </div> <p>You have already seen square brackets like these in Section <a class="reference internal" href="C02_Basics.html#proving-identities-in-algebraic-structures"><span class="std std-numref">Section 2.2</span></a>, though we still haven’t explained what they mean. For concreteness, we will stick to the real numbers for most of our examples, but it is worth knowing that mathlib contains definitions and theorems that work at a high level of generality.</p> <p id="index-3">For another example of a hidden universal quantifier, mathlib defines a predicate <code class="docutils literal notranslate"><span class="pre">Monotone</span></code>, which says that a function is nondecreasing in its arguments:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">Monotone</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∀</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span><span class="o">},</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">→</span> <span class="n">f</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">f</span> <span class="n">b</span> <span class="o">:=</span> <span class="bp">@</span><span class="n">h</span> </pre></div> </div> <p>The property <code class="docutils literal notranslate"><span class="pre">Monotone</span> <span class="pre">f</span></code> is defined to be exactly the expression after the colon. We need to put the <code class="docutils literal notranslate"><span class="pre">@</span></code> symbol before <code class="docutils literal notranslate"><span class="pre">h</span></code> because if we don’t, Lean expands the implicit arguments to <code class="docutils literal notranslate"><span class="pre">h</span></code> and inserts placeholders.</p> <p>Proving statements about monotonicity involves using <code class="docutils literal notranslate"><span class="pre">intro</span></code> to introduce two variables, say, <code class="docutils literal notranslate"><span class="pre">a</span></code> and <code class="docutils literal notranslate"><span class="pre">b</span></code>, and the hypothesis <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">≤</span> <span class="pre">b</span></code>. To <em>use</em> a monotonicity hypothesis, you can apply it to suitable arguments and hypotheses, and then apply the resulting expression to the goal. Or you can apply it to the goal and let Lean help you work backwards by displaying the remaining hypotheses as new subgoals.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">mf</span> <span class="o">:</span> <span class="n">Monotone</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">mg</span> <span class="o">:</span> <span class="n">Monotone</span> <span class="n">g</span><span class="o">)</span> <span class="o">:</span> <span class="n">Monotone</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">g</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">a</span> <span class="n">b</span> <span class="n">aleb</span> <span class="n">apply</span> <span class="n">add_le_add</span> <span class="n">apply</span> <span class="n">mf</span> <span class="n">aleb</span> <span class="n">apply</span> <span class="n">mg</span> <span class="n">aleb</span> </pre></div> </div> <p>When a proof is this short, it is often convenient to give a proof term instead. To describe a proof that temporarily introduces objects <code class="docutils literal notranslate"><span class="pre">a</span></code> and <code class="docutils literal notranslate"><span class="pre">b</span></code> and a hypothesis <code class="docutils literal notranslate"><span class="pre">aleb</span></code>, Lean uses the notation <code class="docutils literal notranslate"><span class="pre">fun</span> <span class="pre">a</span> <span class="pre">b</span> <span class="pre">aleb</span> <span class="pre">=></span> <span class="pre">...</span></code>. This is analogous to the way that an expression like <code class="docutils literal notranslate"><span class="pre">fun</span> <span class="pre">x</span> <span class="pre">=></span> <span class="pre">x^2</span></code> describes a function by temporarily naming an object, <code class="docutils literal notranslate"><span class="pre">x</span></code>, and then using it to describe a value. So the <code class="docutils literal notranslate"><span class="pre">intro</span></code> command in the previous proof corresponds to the lambda abstraction in the next proof term. The <code class="docutils literal notranslate"><span class="pre">apply</span></code> commands then correspond to building the application of the theorem to its arguments.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">mf</span> <span class="o">:</span> <span class="n">Monotone</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">mg</span> <span class="o">:</span> <span class="n">Monotone</span> <span class="n">g</span><span class="o">)</span> <span class="o">:</span> <span class="n">Monotone</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">g</span> <span class="n">x</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">a</span> <span class="n">b</span> <span class="n">aleb</span> <span class="bp">=></span> <span class="n">add_le_add</span> <span class="o">(</span><span class="n">mf</span> <span class="n">aleb</span><span class="o">)</span> <span class="o">(</span><span class="n">mg</span> <span class="n">aleb</span><span class="o">)</span> </pre></div> </div> <p>Here is a useful trick: if you start writing the proof term <code class="docutils literal notranslate"><span class="pre">fun</span> <span class="pre">a</span> <span class="pre">b</span> <span class="pre">aleb</span> <span class="pre">=></span> <span class="pre">_</span></code> using an underscore where the rest of the expression should go, Lean will flag an error, indicating that it can’t guess the value of that expression. If you check the Lean Goal window in VS Code or hover over the squiggly error marker, Lean will show you the goal that the remaining expression has to solve.</p> <p>Try proving these, with either tactics or proof terms:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">c</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">mf</span> <span class="o">:</span> <span class="n">Monotone</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">nnc</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">c</span><span class="o">)</span> <span class="o">:</span> <span class="n">Monotone</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">c</span> <span class="bp">*</span> <span class="n">f</span> <span class="n">x</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">mf</span> <span class="o">:</span> <span class="n">Monotone</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">mg</span> <span class="o">:</span> <span class="n">Monotone</span> <span class="n">g</span><span class="o">)</span> <span class="o">:</span> <span class="n">Monotone</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="o">(</span><span class="n">g</span> <span class="n">x</span><span class="o">)</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>Here are some more examples. A function <span class="math notranslate nohighlight">\(f\)</span> from <span class="math notranslate nohighlight">\(\Bbb R\)</span> to <span class="math notranslate nohighlight">\(\Bbb R\)</span> is said to be <em>even</em> if <span class="math notranslate nohighlight">\(f(-x) = f(x)\)</span> for every <span class="math notranslate nohighlight">\(x\)</span>, and <em>odd</em> if <span class="math notranslate nohighlight">\(f(-x) = -f(x)\)</span> for every <span class="math notranslate nohighlight">\(x\)</span>. The following example defines these two notions formally and establishes one fact about them. You can complete the proofs of the others.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">FnEven</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="kt">Prop</span> <span class="o">:=</span> <span class="bp">∀</span> <span class="n">x</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">f</span> <span class="o">(</span><span class="bp">-</span><span class="n">x</span><span class="o">)</span> <span class="kd">def</span> <span class="n">FnOdd</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="kt">Prop</span> <span class="o">:=</span> <span class="bp">∀</span> <span class="n">x</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">=</span> <span class="bp">-</span><span class="n">f</span> <span class="o">(</span><span class="bp">-</span><span class="n">x</span><span class="o">)</span> <span class="kd">example</span> <span class="o">(</span><span class="n">ef</span> <span class="o">:</span> <span class="n">FnEven</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">eg</span> <span class="o">:</span> <span class="n">FnEven</span> <span class="n">g</span><span class="o">)</span> <span class="o">:</span> <span class="n">FnEven</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">g</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">x</span> <span class="k">calc</span> <span class="o">(</span><span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">g</span> <span class="n">x</span><span class="o">)</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">g</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="n">_</span> <span class="bp">=</span> <span class="n">f</span> <span class="o">(</span><span class="bp">-</span><span class="n">x</span><span class="o">)</span> <span class="bp">+</span> <span class="n">g</span> <span class="o">(</span><span class="bp">-</span><span class="n">x</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">ef</span><span class="o">,</span> <span class="n">eg</span><span class="o">]</span> <span class="kd">example</span> <span class="o">(</span><span class="n">of</span> <span class="o">:</span> <span class="n">FnOdd</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">og</span> <span class="o">:</span> <span class="n">FnOdd</span> <span class="n">g</span><span class="o">)</span> <span class="o">:</span> <span class="n">FnEven</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="n">x</span> <span class="bp">*</span> <span class="n">g</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">ef</span> <span class="o">:</span> <span class="n">FnEven</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">og</span> <span class="o">:</span> <span class="n">FnOdd</span> <span class="n">g</span><span class="o">)</span> <span class="o">:</span> <span class="n">FnOdd</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="n">x</span> <span class="bp">*</span> <span class="n">g</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">ef</span> <span class="o">:</span> <span class="n">FnEven</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">og</span> <span class="o">:</span> <span class="n">FnOdd</span> <span class="n">g</span><span class="o">)</span> <span class="o">:</span> <span class="n">FnEven</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="o">(</span><span class="n">g</span> <span class="n">x</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p id="index-4">The first proof can be shortened using <code class="docutils literal notranslate"><span class="pre">dsimp</span></code> or <code class="docutils literal notranslate"><span class="pre">change</span></code> to get rid of the lambda. But you can check that the subsequent <code class="docutils literal notranslate"><span class="pre">rw</span></code> won’t work unless we get rid of the lambda explicitly, because otherwise it cannot find the patterns <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">g</span> <span class="pre">x</span></code> in the expression. Contrary to some other tactics, <code class="docutils literal notranslate"><span class="pre">rw</span></code> operates on the syntactic level, it won’t unfold definitions or apply reductions for you (it has a variant called <code class="docutils literal notranslate"><span class="pre">erw</span></code> that tries a little harder in this direction, but not much harder).</p> <p>You can find implicit universal quantifiers all over the place, once you know how to spot them. Mathlib includes a good library for rudimentary set theory. Lean’s logical foundation imposes the restriction that when we talk about sets, we are always talking about sets of elements of some type. If <code class="docutils literal notranslate"><span class="pre">x</span></code> has type <code class="docutils literal notranslate"><span class="pre">α</span></code> and <code class="docutils literal notranslate"><span class="pre">s</span></code> has type <code class="docutils literal notranslate"><span class="pre">Set</span> <span class="pre">α</span></code>, then <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span></code> is a proposition that asserts that <code class="docutils literal notranslate"><span class="pre">x</span></code> is an element of <code class="docutils literal notranslate"><span class="pre">s</span></code>. If <code class="docutils literal notranslate"><span class="pre">s</span></code> and <code class="docutils literal notranslate"><span class="pre">t</span></code> are of type <code class="docutils literal notranslate"><span class="pre">Set</span> <span class="pre">α</span></code>, then the subset relation <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">⊆</span> <span class="pre">t</span></code> is defined to mean <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">{x</span> <span class="pre">:</span> <span class="pre">α},</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span> <span class="pre">→</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">t</span></code>. The variable in the quantifier is marked implicit so that given <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">:</span> <span class="pre">s</span> <span class="pre">⊆</span> <span class="pre">t</span></code> and <code class="docutils literal notranslate"><span class="pre">h'</span> <span class="pre">:</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span></code>, we can write <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">h'</span></code> as justification for <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">∈</span> <span class="pre">t</span></code>. The following example provides a tactic proof and a proof term justifying the reflexivity of the subset relation, and asks you to do the same for transitivity.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">(</span><span class="n">r</span> <span class="n">s</span> <span class="n">t</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">α</span><span class="o">)</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="n">s</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">xs</span> <span class="n">exact</span> <span class="n">xs</span> <span class="kd">theorem</span> <span class="n">Subset.refl</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="n">s</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">x</span> <span class="n">xs</span> <span class="bp">=></span> <span class="n">xs</span> <span class="kd">theorem</span> <span class="n">Subset.trans</span> <span class="o">:</span> <span class="n">r</span> <span class="bp">⊆</span> <span class="n">s</span> <span class="bp">→</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="n">t</span> <span class="bp">→</span> <span class="n">r</span> <span class="bp">⊆</span> <span class="n">t</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Just as we defined <code class="docutils literal notranslate"><span class="pre">FnUb</span></code> for functions, we can define <code class="docutils literal notranslate"><span class="pre">SetUb</span> <span class="pre">s</span> <span class="pre">a</span></code> to mean that <code class="docutils literal notranslate"><span class="pre">a</span></code> is an upper bound on the set <code class="docutils literal notranslate"><span class="pre">s</span></code>, assuming <code class="docutils literal notranslate"><span class="pre">s</span></code> is a set of elements of some type that has an order associated with it. In the next example, we ask you to prove that if <code class="docutils literal notranslate"><span class="pre">a</span></code> is a bound on <code class="docutils literal notranslate"><span class="pre">s</span></code> and <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">≤</span> <span class="pre">b</span></code>, then <code class="docutils literal notranslate"><span class="pre">b</span></code> is a bound on <code class="docutils literal notranslate"><span class="pre">s</span></code> as well.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">PartialOrder</span> <span class="n">α</span><span class="o">]</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">α</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="kd">def</span> <span class="n">SetUb</span> <span class="o">(</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">α</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="o">:=</span> <span class="bp">∀</span> <span class="n">x</span><span class="o">,</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s</span> <span class="bp">→</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">a</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">SetUb</span> <span class="n">s</span> <span class="n">a</span><span class="o">)</span> <span class="o">(</span><span class="n">h'</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span><span class="o">)</span> <span class="o">:</span> <span class="n">SetUb</span> <span class="n">s</span> <span class="n">b</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p id="index-5">We close this section with one last important example. A function <span class="math notranslate nohighlight">\(f\)</span> is said to be <em>injective</em> if for every <span class="math notranslate nohighlight">\(x_1\)</span> and <span class="math notranslate nohighlight">\(x_2\)</span>, if <span class="math notranslate nohighlight">\(f(x_1) = f(x_2)\)</span> then <span class="math notranslate nohighlight">\(x_1 = x_2\)</span>. Mathlib defines <code class="docutils literal notranslate"><span class="pre">Function.Injective</span> <span class="pre">f</span></code> with <code class="docutils literal notranslate"><span class="pre">x₁</span></code> and <code class="docutils literal notranslate"><span class="pre">x₂</span></code> implicit. The next example shows that, on the real numbers, any function that adds a constant is injective. We then ask you to show that multiplication by a nonzero constant is also injective.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">open</span> <span class="n">Function</span> <span class="kd">example</span> <span class="o">(</span><span class="n">c</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">Injective</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">x</span> <span class="bp">+</span> <span class="n">c</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">x₁</span> <span class="n">x₂</span> <span class="n">h'</span> <span class="n">exact</span> <span class="o">(</span><span class="n">add_left_inj</span> <span class="n">c</span><span class="o">)</span><span class="bp">.</span><span class="n">mp</span> <span class="n">h'</span> <span class="kd">example</span> <span class="o">{</span><span class="n">c</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">≠</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="n">Injective</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">c</span> <span class="bp">*</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Finally, show that the composition of two injective functions is injective:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">{</span><span class="n">β</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">{</span><span class="n">γ</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="kd">variable</span> <span class="o">{</span><span class="n">g</span> <span class="o">:</span> <span class="n">β</span> <span class="bp">→</span> <span class="n">γ</span><span class="o">}</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">β</span><span class="o">}</span> <span class="kd">example</span> <span class="o">(</span><span class="n">injg</span> <span class="o">:</span> <span class="n">Injective</span> <span class="n">g</span><span class="o">)</span> <span class="o">(</span><span class="n">injf</span> <span class="o">:</span> <span class="n">Injective</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">Injective</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">g</span> <span class="o">(</span><span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> </section> <section id="the-existential-quantifier"> <span id="id3"></span><h2><span class="section-number">3.2. </span>The Existential Quantifier<a class="headerlink" href="#the-existential-quantifier" title="Permalink to this heading"></a></h2> <p>The existential quantifier, which can be entered as <code class="docutils literal notranslate"><span class="pre">\ex</span></code> in VS Code, is used to represent the phrase “there exists.” The formal expression <code class="docutils literal notranslate"><span class="pre">∃</span> <span class="pre">x</span> <span class="pre">:</span> <span class="pre">ℝ,</span> <span class="pre">2</span> <span class="pre"><</span> <span class="pre">x</span> <span class="pre">∧</span> <span class="pre">x</span> <span class="pre"><</span> <span class="pre">3</span></code> in Lean says that there is a real number between 2 and 3. (We will discuss the conjunction symbol, <code class="docutils literal notranslate"><span class="pre">∧</span></code>, in <a class="reference internal" href="#conjunction-and-biimplication"><span class="std std-numref">Section 3.4</span></a>.) The canonical way to prove such a statement is to exhibit a real number and show that it has the stated property. The number 2.5, which we can enter as <code class="docutils literal notranslate"><span class="pre">5</span> <span class="pre">/</span> <span class="pre">2</span></code> or <code class="docutils literal notranslate"><span class="pre">(5</span> <span class="pre">:</span> <span class="pre">ℝ)</span> <span class="pre">/</span> <span class="pre">2</span></code> when Lean cannot infer from context that we have the real numbers in mind, has the required property, and the <code class="docutils literal notranslate"><span class="pre">norm_num</span></code> tactic can prove that it meets the description.</p> <p id="index-6">There are a few ways we can put the information together. Given a goal that begins with an existential quantifier, the <code class="docutils literal notranslate"><span class="pre">use</span></code> tactic is used to provide the object, leaving the goal of proving the property.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">,</span> <span class="mi">2</span> <span class="bp"><</span> <span class="n">x</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp"><</span> <span class="mi">3</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">use</span> <span class="mi">5</span> <span class="bp">/</span> <span class="mi">2</span> <span class="n">norm_num</span> </pre></div> </div> <p id="index-7">Alternatively, we can use Lean’s <em>anonymous constructor</em> notation to construct the proof.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">,</span> <span class="mi">2</span> <span class="bp"><</span> <span class="n">x</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp"><</span> <span class="mi">3</span> <span class="o">:=</span> <span class="k">have</span> <span class="n">h</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp"><</span> <span class="o">(</span><span class="mi">5</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="bp">/</span> <span class="mi">2</span> <span class="bp">∧</span> <span class="o">(</span><span class="mi">5</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="bp">/</span> <span class="mi">2</span> <span class="bp"><</span> <span class="mi">3</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">norm_num</span> <span class="o">⟨</span><span class="mi">5</span> <span class="bp">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">h</span><span class="o">⟩</span> </pre></div> </div> <p>The left and right angle brackets, which can be entered as <code class="docutils literal notranslate"><span class="pre">\<</span></code> and <code class="docutils literal notranslate"><span class="pre">\></span></code> respectively, tell Lean to put together the given data using whatever construction is appropriate for the current goal. We can use the notation without going first into tactic mode:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">,</span> <span class="mi">2</span> <span class="bp"><</span> <span class="n">x</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp"><</span> <span class="mi">3</span> <span class="o">:=</span> <span class="o">⟨</span><span class="mi">5</span> <span class="bp">/</span> <span class="mi">2</span><span class="o">,</span> <span class="kd">by</span> <span class="n">norm_num</span><span class="o">⟩</span> </pre></div> </div> <p>So now we know how to <em>prove</em> an exists statement. But how do we <em>use</em> one? If we know that there exists an object with a certain property, we should be able to give a name to an arbitrary one and reason about it. For example, remember the predicates <code class="docutils literal notranslate"><span class="pre">FnUb</span> <span class="pre">f</span> <span class="pre">a</span></code> and <code class="docutils literal notranslate"><span class="pre">FnLb</span> <span class="pre">f</span> <span class="pre">a</span></code> from the last section, which say that <code class="docutils literal notranslate"><span class="pre">a</span></code> is an upper bound or lower bound on <code class="docutils literal notranslate"><span class="pre">f</span></code>, respectively. We can use the existential quantifier to say that “<code class="docutils literal notranslate"><span class="pre">f</span></code> is bounded” without specifying the bound:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">FnUb</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="kt">Prop</span> <span class="o">:=</span> <span class="bp">∀</span> <span class="n">x</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">a</span> <span class="kd">def</span> <span class="n">FnLb</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="kt">Prop</span> <span class="o">:=</span> <span class="bp">∀</span> <span class="n">x</span><span class="o">,</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">f</span> <span class="n">x</span> <span class="kd">def</span> <span class="n">FnHasUb</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:=</span> <span class="bp">∃</span> <span class="n">a</span><span class="o">,</span> <span class="n">FnUb</span> <span class="n">f</span> <span class="n">a</span> <span class="kd">def</span> <span class="n">FnHasLb</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:=</span> <span class="bp">∃</span> <span class="n">a</span><span class="o">,</span> <span class="n">FnLb</span> <span class="n">f</span> <span class="n">a</span> </pre></div> </div> <p>We can use the theorem <code class="docutils literal notranslate"><span class="pre">FnUb_add</span></code> from the last section to prove that if <code class="docutils literal notranslate"><span class="pre">f</span></code> and <code class="docutils literal notranslate"><span class="pre">g</span></code> have upper bounds, then so does <code class="docutils literal notranslate"><span class="pre">fun</span> <span class="pre">x</span> <span class="pre">=></span> <span class="pre">f</span> <span class="pre">x</span> <span class="pre">+</span> <span class="pre">g</span> <span class="pre">x</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">f</span> <span class="n">g</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">}</span> <span class="kd">example</span> <span class="o">(</span><span class="n">ubf</span> <span class="o">:</span> <span class="n">FnHasUb</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">ubg</span> <span class="o">:</span> <span class="n">FnHasUb</span> <span class="n">g</span><span class="o">)</span> <span class="o">:</span> <span class="n">FnHasUb</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">g</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">cases'</span> <span class="n">ubf</span> <span class="k">with</span> <span class="n">a</span> <span class="n">ubfa</span> <span class="n">cases'</span> <span class="n">ubg</span> <span class="k">with</span> <span class="n">b</span> <span class="n">ubgb</span> <span class="n">use</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="n">apply</span> <span class="n">fnUb_add</span> <span class="n">ubfa</span> <span class="n">ubgb</span> </pre></div> </div> <p id="index-8">The <code class="docutils literal notranslate"><span class="pre">cases'</span></code> tactic unpacks the information in the existential quantifier. Given the hypothesis <code class="docutils literal notranslate"><span class="pre">ubf</span></code> that there is an upper bound for <code class="docutils literal notranslate"><span class="pre">f</span></code>, <code class="docutils literal notranslate"><span class="pre">cases'</span></code> adds a new variable for an upper bound to the context, together with the hypothesis that it has the given property. The <code class="docutils literal notranslate"><span class="pre">with</span></code> clause allows us to specify the names we want Lean to use. The goal is left unchanged; what <em>has</em> changed is that we can now use the new object and the new hypothesis to prove the goal. This is a common pattern in mathematics: we unpack objects whose existence is asserted or implied by some hypothesis, and then use it to establish the existence of something else.</p> <p>Try using this pattern to establish the following. You might find it useful to turn some of the examples from the last section into named theorems, as we did with <code class="docutils literal notranslate"><span class="pre">fn_ub_add</span></code>, or you can insert the arguments directly into the proofs.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">lbf</span> <span class="o">:</span> <span class="n">FnHasLb</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">lbg</span> <span class="o">:</span> <span class="n">FnHasLb</span> <span class="n">g</span><span class="o">)</span> <span class="o">:</span> <span class="n">FnHasLb</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">g</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">{</span><span class="n">c</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">ubf</span> <span class="o">:</span> <span class="n">FnHasUb</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">≥</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="n">FnHasUb</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">c</span> <span class="bp">*</span> <span class="n">f</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p id="index-9">The task of unpacking information in a hypothesis is so important that Lean and mathlib provide a number of ways to do it. A cousin of the <code class="docutils literal notranslate"><span class="pre">cases'</span></code> tactic, <code class="docutils literal notranslate"><span class="pre">rcases</span></code>, is more flexible in that it allows us to unpack nested data. (The “r” stands for “recursive.”) In the <code class="docutils literal notranslate"><span class="pre">with</span></code> clause for unpacking an existential quantifier, we name the object and the hypothesis by presenting them as a pattern <code class="docutils literal notranslate"><span class="pre">⟨a,</span> <span class="pre">h⟩</span></code> that <code class="docutils literal notranslate"><span class="pre">rcases</span></code> then tries to match. The <code class="docutils literal notranslate"><span class="pre">rintro</span></code> tactic is a combination of <code class="docutils literal notranslate"><span class="pre">intro</span></code> and <code class="docutils literal notranslate"><span class="pre">rcases</span></code>. These examples illustrate their use:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">ubf</span> <span class="o">:</span> <span class="n">FnHasUb</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">ubg</span> <span class="o">:</span> <span class="n">FnHasUb</span> <span class="n">g</span><span class="o">)</span> <span class="o">:</span> <span class="n">FnHasUb</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">g</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rcases</span> <span class="n">ubf</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">a</span><span class="o">,</span> <span class="n">ubfa</span><span class="o">⟩</span> <span class="n">rcases</span> <span class="n">ubg</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">b</span><span class="o">,</span> <span class="n">ubgb</span><span class="o">⟩</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">,</span> <span class="n">fnUb_add</span> <span class="n">ubfa</span> <span class="n">ubgb</span><span class="o">⟩</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">FnHasUb</span> <span class="n">f</span> <span class="bp">→</span> <span class="n">FnHasUb</span> <span class="n">g</span> <span class="bp">→</span> <span class="n">FnHasUb</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">g</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rintro</span> <span class="o">⟨</span><span class="n">a</span><span class="o">,</span> <span class="n">ubfa</span><span class="o">⟩</span> <span class="o">⟨</span><span class="n">b</span><span class="o">,</span> <span class="n">ubgb</span><span class="o">⟩</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">,</span> <span class="n">fnUb_add</span> <span class="n">ubfa</span> <span class="n">ubgb</span><span class="o">⟩</span> </pre></div> </div> <p>In fact, Lean also supports a pattern-matching lambda in expressions and proof terms:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">FnHasUb</span> <span class="n">f</span> <span class="bp">→</span> <span class="n">FnHasUb</span> <span class="n">g</span> <span class="bp">→</span> <span class="n">FnHasUb</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">g</span> <span class="n">x</span> <span class="o">:=</span> <span class="k">fun</span> <span class="o">⟨</span><span class="n">a</span><span class="o">,</span> <span class="n">ubfa</span><span class="o">⟩</span> <span class="o">⟨</span><span class="n">b</span><span class="o">,</span> <span class="n">ubgb</span><span class="o">⟩</span> <span class="bp">=></span> <span class="o">⟨</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">,</span> <span class="n">fnUb_add</span> <span class="n">ubfa</span> <span class="n">ubgb</span><span class="o">⟩</span> </pre></div> </div> <p>These are power-user moves, and there is no harm in favoring the use of <code class="docutils literal notranslate"><span class="pre">cases'</span></code> until you are more comfortable with the existential quantifier. But we will come to learn that all of these tools, including <code class="docutils literal notranslate"><span class="pre">cases'</span></code>, <code class="docutils literal notranslate"><span class="pre">use</span></code>, and the anonymous constructors, are like Swiss army knives when it comes to theorem proving. They can be used for a wide range of purposes, not just for unpacking exists statements.</p> <p>To illustrate one way that <code class="docutils literal notranslate"><span class="pre">rcases</span></code> can be used, we prove an old mathematical chestnut: if two integers <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code> can each be written as a sum of two squares, then so can their product, <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">*</span> <span class="pre">y</span></code>. In fact, the statement is true for any commutative ring, not just the integers. In the next example, <code class="docutils literal notranslate"><span class="pre">rcases</span></code> unpacks two existential quantifiers at once. We then provide the magic values needed to express <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">*</span> <span class="pre">y</span></code> as a sum of squares as a list to the <code class="docutils literal notranslate"><span class="pre">use</span></code> statement, and we use <code class="docutils literal notranslate"><span class="pre">ring</span></code> to verify that they work.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">CommRing</span> <span class="n">α</span><span class="o">]</span> <span class="kd">def</span> <span class="n">SumOfSquares</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="o">:=</span> <span class="bp">∃</span> <span class="n">a</span> <span class="n">b</span><span class="o">,</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">^</span> <span class="mi">2</span> <span class="kd">theorem</span> <span class="n">sumOfSquares_mul</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">α</span><span class="o">}</span> <span class="o">(</span><span class="n">sosx</span> <span class="o">:</span> <span class="n">SumOfSquares</span> <span class="n">x</span><span class="o">)</span> <span class="o">(</span><span class="n">sosy</span> <span class="o">:</span> <span class="n">SumOfSquares</span> <span class="n">y</span><span class="o">)</span> <span class="o">:</span> <span class="n">SumOfSquares</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">y</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rcases</span> <span class="n">sosx</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">a</span><span class="o">,</span> <span class="n">b</span><span class="o">,</span> <span class="n">xeq</span><span class="o">⟩</span> <span class="n">rcases</span> <span class="n">sosy</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">c</span><span class="o">,</span> <span class="n">d</span><span class="o">,</span> <span class="n">yeq</span><span class="o">⟩</span> <span class="n">rw</span> <span class="o">[</span><span class="n">xeq</span><span class="o">,</span> <span class="n">yeq</span><span class="o">]</span> <span class="n">use</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">-</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">d</span><span class="o">,</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">d</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">c</span> <span class="n">ring</span> </pre></div> </div> <p>This proof doesn’t provide much insight, but here is one way to motivate it. A <em>Gaussian integer</em> is a number of the form <span class="math notranslate nohighlight">\(a + bi\)</span> where <span class="math notranslate nohighlight">\(a\)</span> and <span class="math notranslate nohighlight">\(b\)</span> are integers and <span class="math notranslate nohighlight">\(i = \sqrt{-1}\)</span>. The <em>norm</em> of the Gaussian integer <span class="math notranslate nohighlight">\(a + bi\)</span> is, by definition, <span class="math notranslate nohighlight">\(a^2 + b^2\)</span>. So the norm of a Gaussian integer is a sum of squares, and any sum of squares can be expressed in this way. The theorem above reflects the fact that norm of a product of Gaussian integers is the product of their norms: if <span class="math notranslate nohighlight">\(x\)</span> is the norm of <span class="math notranslate nohighlight">\(a + bi\)</span> and <span class="math notranslate nohighlight">\(y\)</span> in the norm of <span class="math notranslate nohighlight">\(c + di\)</span>, then <span class="math notranslate nohighlight">\(xy\)</span> is the norm of <span class="math notranslate nohighlight">\((a + bi) (c + di)\)</span>. Our cryptic proof illustrates the fact that the proof that is easiest to formalize isn’t always the most perspicuous one. In the chapters to come, we will provide you with the means to define the Gaussian integers and use them to provide an alternative proof.</p> <p>The pattern of unpacking an equation inside an existential quantifier and then using it to rewrite an expression in the goal comes up often, so much so that the <code class="docutils literal notranslate"><span class="pre">rcases</span></code> tactic provides an abbreviation: if you use the keyword <code class="docutils literal notranslate"><span class="pre">rfl</span></code> in place of a new identifier, <code class="docutils literal notranslate"><span class="pre">rcases</span></code> does the rewriting automatically (this trick doesn’t work with pattern-matching lambdas).</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">sumOfSquares_mul'</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">α</span><span class="o">}</span> <span class="o">(</span><span class="n">sosx</span> <span class="o">:</span> <span class="n">SumOfSquares</span> <span class="n">x</span><span class="o">)</span> <span class="o">(</span><span class="n">sosy</span> <span class="o">:</span> <span class="n">SumOfSquares</span> <span class="n">y</span><span class="o">)</span> <span class="o">:</span> <span class="n">SumOfSquares</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">y</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rcases</span> <span class="n">sosx</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">a</span><span class="o">,</span> <span class="n">b</span><span class="o">,</span> <span class="n">rfl</span><span class="o">⟩</span> <span class="n">rcases</span> <span class="n">sosy</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">c</span><span class="o">,</span> <span class="n">d</span><span class="o">,</span> <span class="n">rfl</span><span class="o">⟩</span> <span class="n">use</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">-</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">d</span><span class="o">,</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">d</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">c</span> <span class="n">ring</span> </pre></div> </div> <p>As with the universal quantifier, you can find existential quantifiers hidden all over if you know how to spot them. For example, divisibility is implicitly an “exists” statement.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">divab</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">∣</span> <span class="n">b</span><span class="o">)</span> <span class="o">(</span><span class="n">divbc</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">∣</span> <span class="n">c</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">∣</span> <span class="n">c</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">cases'</span> <span class="n">divab</span> <span class="k">with</span> <span class="n">d</span> <span class="n">beq</span> <span class="n">cases'</span> <span class="n">divbc</span> <span class="k">with</span> <span class="n">e</span> <span class="n">ceq</span> <span class="n">rw</span> <span class="o">[</span><span class="n">ceq</span><span class="o">,</span> <span class="n">beq</span><span class="o">]</span> <span class="n">use</span> <span class="n">d</span> <span class="bp">*</span> <span class="n">e</span><span class="bp">;</span> <span class="n">ring</span> </pre></div> </div> <p>And once again, this provides a nice setting for using <code class="docutils literal notranslate"><span class="pre">rcases</span></code> with <code class="docutils literal notranslate"><span class="pre">rfl</span></code>. Try it out in the proof above. It feels pretty good!</p> <p>Then try proving the following:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">divab</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">∣</span> <span class="n">b</span><span class="o">)</span> <span class="o">(</span><span class="n">divac</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">∣</span> <span class="n">c</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">∣</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">c</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p id="index-10">For another important example, a function <span class="math notranslate nohighlight">\(f : \alpha \to \beta\)</span> is said to be <em>surjective</em> if for every <span class="math notranslate nohighlight">\(y\)</span> in the codomain, <span class="math notranslate nohighlight">\(\beta\)</span>, there is an <span class="math notranslate nohighlight">\(x\)</span> in the domain, <span class="math notranslate nohighlight">\(\alpha\)</span>, such that <span class="math notranslate nohighlight">\(f(x) = y\)</span>. Notice that this statement includes both a universal and an existential quantifier, which explains why the next example makes use of both <code class="docutils literal notranslate"><span class="pre">intro</span></code> and <code class="docutils literal notranslate"><span class="pre">use</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">c</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">:</span> <span class="n">Surjective</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">x</span> <span class="bp">+</span> <span class="n">c</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">use</span> <span class="n">x</span> <span class="bp">-</span> <span class="n">c</span> <span class="n">dsimp</span><span class="bp">;</span> <span class="n">ring</span> </pre></div> </div> <p>Try this example yourself:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">c</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">≠</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="n">Surjective</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">c</span> <span class="bp">*</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p id="index-11">At this point, it is worth mentioning that there is a tactic, <cite>field_simp</cite>, that will often clear denominators in a useful way. It can be used in conjunction with the <code class="docutils literal notranslate"><span class="pre">ring</span></code> tactic.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">-</span> <span class="n">y</span> <span class="bp">≠</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">-</span> <span class="n">y</span> <span class="bp">^</span> <span class="mi">2</span><span class="o">)</span> <span class="bp">/</span> <span class="o">(</span><span class="n">x</span> <span class="bp">-</span> <span class="n">y</span><span class="o">)</span> <span class="bp">=</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">field_simp</span> <span class="o">[</span><span class="n">h</span><span class="o">]</span> <span class="n">ring</span> </pre></div> </div> <p>You can use the theorem <code class="docutils literal notranslate"><span class="pre">div_mul_cancel</span></code>. The next example uses a surjectivity hypothesis by applying it to a suitable value. Note that you can use <code class="docutils literal notranslate"><span class="pre">cases'</span></code> with any expression, not just a hypothesis.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">Surjective</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">=</span> <span class="mi">4</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">cases'</span> <span class="n">h</span> <span class="mi">2</span> <span class="k">with</span> <span class="n">x</span> <span class="n">hx</span> <span class="n">use</span> <span class="n">x</span> <span class="n">rw</span> <span class="o">[</span><span class="n">hx</span><span class="o">]</span> <span class="n">norm_num</span> </pre></div> </div> <p>See if you can use these methods to show that the composition of surjective functions is surjective.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">{</span><span class="n">β</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">{</span><span class="n">γ</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="kd">variable</span> <span class="o">{</span><span class="n">g</span> <span class="o">:</span> <span class="n">β</span> <span class="bp">→</span> <span class="n">γ</span><span class="o">}</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">β</span><span class="o">}</span> <span class="kd">example</span> <span class="o">(</span><span class="n">surjg</span> <span class="o">:</span> <span class="n">Surjective</span> <span class="n">g</span><span class="o">)</span> <span class="o">(</span><span class="n">surjf</span> <span class="o">:</span> <span class="n">Surjective</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">Surjective</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">g</span> <span class="o">(</span><span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> </section> <section id="negation"> <span id="id4"></span><h2><span class="section-number">3.3. </span>Negation<a class="headerlink" href="#negation" title="Permalink to this heading"></a></h2> <p>The symbol <code class="docutils literal notranslate"><span class="pre">¬</span></code> is meant to express negation, so <code class="docutils literal notranslate"><span class="pre">¬</span> <span class="pre">x</span> <span class="pre"><</span> <span class="pre">y</span></code> says that <code class="docutils literal notranslate"><span class="pre">x</span></code> is not less than <code class="docutils literal notranslate"><span class="pre">y</span></code>, <code class="docutils literal notranslate"><span class="pre">¬</span> <span class="pre">x</span> <span class="pre">=</span> <span class="pre">y</span></code> (or, equivalently, <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">≠</span> <span class="pre">y</span></code>) says that <code class="docutils literal notranslate"><span class="pre">x</span></code> is not equal to <code class="docutils literal notranslate"><span class="pre">y</span></code>, and <code class="docutils literal notranslate"><span class="pre">¬</span> <span class="pre">∃</span> <span class="pre">z,</span> <span class="pre">x</span> <span class="pre"><</span> <span class="pre">z</span> <span class="pre">∧</span> <span class="pre">z</span> <span class="pre"><</span> <span class="pre">y</span></code> says that there does not exist a <code class="docutils literal notranslate"><span class="pre">z</span></code> strictly between <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code>. In Lean, the notation <code class="docutils literal notranslate"><span class="pre">¬</span> <span class="pre">A</span></code> abbreviates <code class="docutils literal notranslate"><span class="pre">A</span> <span class="pre">→</span> <span class="pre">False</span></code>, which you can think of as saying that <code class="docutils literal notranslate"><span class="pre">A</span></code> implies a contradiction. Practically speaking, this means that you already know something about how to work with negations: you can prove <code class="docutils literal notranslate"><span class="pre">¬</span> <span class="pre">A</span></code> by introducing a hypothesis <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">:</span> <span class="pre">A</span></code> and proving <code class="docutils literal notranslate"><span class="pre">False</span></code>, and if you have <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">:</span> <span class="pre">¬</span> <span class="pre">A</span></code> and <code class="docutils literal notranslate"><span class="pre">h'</span> <span class="pre">:</span> <span class="pre">A</span></code>, then applying <code class="docutils literal notranslate"><span class="pre">h</span></code> to <code class="docutils literal notranslate"><span class="pre">h'</span></code> yields <code class="docutils literal notranslate"><span class="pre">False</span></code>.</p> <p>To illustrate, consider the irreflexivity principle <code class="docutils literal notranslate"><span class="pre">lt_irrefl</span></code> for a strict order, which says that we have <code class="docutils literal notranslate"><span class="pre">¬</span> <span class="pre">a</span> <span class="pre"><</span> <span class="pre">a</span></code> for every <code class="docutils literal notranslate"><span class="pre">a</span></code>. The asymmetry principle <code class="docutils literal notranslate"><span class="pre">lt_asymm</span></code> says that we have <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre"><</span> <span class="pre">b</span> <span class="pre">→</span> <span class="pre">¬</span> <span class="pre">b</span> <span class="pre"><</span> <span class="pre">a</span></code>. Let’s show that <code class="docutils literal notranslate"><span class="pre">lt_asymm</span></code> follows from <code class="docutils literal notranslate"><span class="pre">lt_irrefl</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">b</span><span class="o">)</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">b</span> <span class="bp"><</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">h'</span> <span class="k">have</span> <span class="o">:</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">a</span> <span class="o">:=</span> <span class="n">lt_trans</span> <span class="n">h</span> <span class="n">h'</span> <span class="n">apply</span> <span class="n">lt_irrefl</span> <span class="n">a</span> <span class="n">this</span> </pre></div> </div> <p id="index-12">This example introduces a couple of new tricks. First, when you use <code class="docutils literal notranslate"><span class="pre">have</span></code> without providing a label, Lean uses the name <code class="docutils literal notranslate"><span class="pre">this</span></code>, providing a convenient way to refer back to it. Also, the <code class="docutils literal notranslate"><span class="pre">from</span></code> tactic is syntactic sugar for <code class="docutils literal notranslate"><span class="pre">exact</span></code>, providing a nice way to justify a <code class="docutils literal notranslate"><span class="pre">have</span></code> with an explicit proof term. But what you should really be paying attention to in this proof is the result of the <code class="docutils literal notranslate"><span class="pre">intro</span></code> tactic, which leaves a goal of <code class="docutils literal notranslate"><span class="pre">False</span></code>, and the fact that we eventually prove <code class="docutils literal notranslate"><span class="pre">False</span></code> by applying <code class="docutils literal notranslate"><span class="pre">lt_irrefl</span></code> to a proof of <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre"><</span> <span class="pre">a</span></code>.</p> <p>Here is another example, which uses the predicate <code class="docutils literal notranslate"><span class="pre">FnHasUb</span></code> defined in the last section, which says that a function has an upper bound.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">x</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">></span> <span class="n">a</span><span class="o">)</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">FnHasUb</span> <span class="n">f</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">fnub</span> <span class="n">cases'</span> <span class="n">fnub</span> <span class="k">with</span> <span class="n">a</span> <span class="n">fnuba</span> <span class="n">cases'</span> <span class="n">h</span> <span class="n">a</span> <span class="k">with</span> <span class="n">x</span> <span class="n">hx</span> <span class="k">have</span> <span class="o">:</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">a</span> <span class="o">:=</span> <span class="n">fnuba</span> <span class="n">x</span> <span class="n">linarith</span> </pre></div> </div> <p>See if you can prove these in a similar way:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">x</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">a</span><span class="o">)</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">FnHasLb</span> <span class="n">f</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">FnHasUb</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">x</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>Mathlib offers a number of useful theorems for relating orders and negations:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="o">(</span><span class="n">not_le_of_gt</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">></span> <span class="n">b</span> <span class="bp">→</span> <span class="bp">¬</span><span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">not_lt_of_ge</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≥</span> <span class="n">b</span> <span class="bp">→</span> <span class="bp">¬</span><span class="n">a</span> <span class="bp"><</span> <span class="n">b</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">lt_of_not_ge</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">a</span> <span class="bp">≥</span> <span class="n">b</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">b</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">le_of_not_gt</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">a</span> <span class="bp">></span> <span class="n">b</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span><span class="o">)</span> </pre></div> </div> <p>Recall the predicate <code class="docutils literal notranslate"><span class="pre">Monotone</span> <span class="pre">f</span></code>, which says that <code class="docutils literal notranslate"><span class="pre">f</span></code> is nondecreasing. Use some of the theorems just enumerated to prove the following:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">Monotone</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">h'</span> <span class="o">:</span> <span class="n">f</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">f</span> <span class="n">b</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span><span class="o">)</span> <span class="o">(</span><span class="n">h'</span> <span class="o">:</span> <span class="n">f</span> <span class="n">b</span> <span class="bp"><</span> <span class="n">f</span> <span class="n">a</span><span class="o">)</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">Monotone</span> <span class="n">f</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Remember that it is often convenient to use <code class="docutils literal notranslate"><span class="pre">linarith</span></code> when a goal follows from linear equations and inequalities that in the context.</p> <p>We can show that the first example in the last snippet cannot be proved if we replace <code class="docutils literal notranslate"><span class="pre"><</span></code> by <code class="docutils literal notranslate"><span class="pre">≤</span></code>. Notice that we can prove the negation of a universally quantified statement by giving a counterexample. Complete the proof.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="bp">¬∀</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">},</span> <span class="n">Monotone</span> <span class="n">f</span> <span class="bp">→</span> <span class="bp">∀</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span><span class="o">},</span> <span class="n">f</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">f</span> <span class="n">b</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">h</span> <span class="k">let</span> <span class="n">f</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">=></span> <span class="o">(</span><span class="mi">0</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="k">have</span> <span class="n">monof</span> <span class="o">:</span> <span class="n">Monotone</span> <span class="n">f</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="n">h'</span> <span class="o">:</span> <span class="n">f</span> <span class="mi">1</span> <span class="bp">≤</span> <span class="n">f</span> <span class="mi">0</span> <span class="o">:=</span> <span class="n">le_refl</span> <span class="n">_</span> <span class="gr">sorry</span> </pre></div> </div> <p id="index-13">This example introduces the <code class="docutils literal notranslate"><span class="pre">let</span></code> tactic, which adds a <em>local definition</em> to the context. If you put the cursor after the <code class="docutils literal notranslate"><span class="pre">let</span></code> command, in the goal window you will see that the definition <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">ℝ</span> <span class="pre">→</span> <span class="pre">ℝ</span> <span class="pre">:=</span> <span class="pre">fun</span> <span class="pre">x</span> <span class="pre">=></span> <span class="pre">0</span></code> has been added to the context. Lean will unfold the definition of <code class="docutils literal notranslate"><span class="pre">f</span></code> when it has to. In particular, when we prove <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">1</span> <span class="pre">≤</span> <span class="pre">f</span> <span class="pre">0</span></code> with <code class="docutils literal notranslate"><span class="pre">le_refl</span></code>, Lean reduces <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">1</span></code> and <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">0</span></code> to <code class="docutils literal notranslate"><span class="pre">0</span></code>.</p> <p>Use <code class="docutils literal notranslate"><span class="pre">le_of_not_gt</span></code> to prove the following:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">ε</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Implicit in many of the proofs we have just done is the fact that if <code class="docutils literal notranslate"><span class="pre">P</span></code> is any property, saying that there is nothing with property <code class="docutils literal notranslate"><span class="pre">P</span></code> is the same as saying that everything fails to have property <code class="docutils literal notranslate"><span class="pre">P</span></code>, and saying that not everything has property <code class="docutils literal notranslate"><span class="pre">P</span></code> is equivalent to saying that something fails to have property <code class="docutils literal notranslate"><span class="pre">P</span></code>. In other words, all four of the following implications are valid (but one of them cannot be proved with what we explained so far):</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">(</span><span class="n">P</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="kt">Prop</span><span class="o">)</span> <span class="o">(</span><span class="n">Q</span> <span class="o">:</span> <span class="kt">Prop</span><span class="o">)</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">¬∃</span> <span class="n">x</span><span class="o">,</span> <span class="n">P</span> <span class="n">x</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span><span class="o">,</span> <span class="bp">¬</span><span class="n">P</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span><span class="o">,</span> <span class="bp">¬</span><span class="n">P</span> <span class="n">x</span><span class="o">)</span> <span class="o">:</span> <span class="bp">¬∃</span> <span class="n">x</span><span class="o">,</span> <span class="n">P</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">¬∀</span> <span class="n">x</span><span class="o">,</span> <span class="n">P</span> <span class="n">x</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span><span class="o">,</span> <span class="bp">¬</span><span class="n">P</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span><span class="o">,</span> <span class="bp">¬</span><span class="n">P</span> <span class="n">x</span><span class="o">)</span> <span class="o">:</span> <span class="bp">¬∀</span> <span class="n">x</span><span class="o">,</span> <span class="n">P</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>The first, second, and fourth are straightforward to prove using the methods you have already seen. We encourage you to try it. The third is more difficult, however, because it concludes that an object exists from the fact that its nonexistence is contradictory. This is an instance of <em>classical</em> mathematical reasoning. We can use proof by contradiction to prove the third implication as follows.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">¬∀</span> <span class="n">x</span><span class="o">,</span> <span class="n">P</span> <span class="n">x</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span><span class="o">,</span> <span class="bp">¬</span><span class="n">P</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">by_contra</span> <span class="n">h'</span> <span class="n">apply</span> <span class="n">h</span> <span class="n">intro</span> <span class="n">x</span> <span class="k">show</span> <span class="n">P</span> <span class="n">x</span> <span class="n">by_contra</span> <span class="n">h''</span> <span class="n">exact</span> <span class="n">h'</span> <span class="o">⟨</span><span class="n">x</span><span class="o">,</span> <span class="n">h''</span><span class="o">⟩</span> </pre></div> </div> <p id="index-14">Make sure you understand how this works. The <code class="docutils literal notranslate"><span class="pre">by_contra</span></code> tactic allows us to prove a goal <code class="docutils literal notranslate"><span class="pre">Q</span></code> by assuming <code class="docutils literal notranslate"><span class="pre">¬</span> <span class="pre">Q</span></code> and deriving a contradiction. In fact, it is equivalent to using the equivalence <code class="docutils literal notranslate"><span class="pre">not_not</span> <span class="pre">:</span> <span class="pre">¬</span> <span class="pre">¬</span> <span class="pre">Q</span> <span class="pre">↔</span> <span class="pre">Q</span></code>. Confirm that you can prove the forward direction of this equivalence using <code class="docutils literal notranslate"><span class="pre">by_contra</span></code>, while the reverse direction follows from the ordinary rules for negation.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">¬¬</span><span class="n">Q</span><span class="o">)</span> <span class="o">:</span> <span class="n">Q</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">Q</span><span class="o">)</span> <span class="o">:</span> <span class="bp">¬¬</span><span class="n">Q</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Use proof by contradiction to establish the following, which is the converse of one of the implications we proved above. (Hint: use <code class="docutils literal notranslate"><span class="pre">intro</span></code> first.)</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">FnHasUb</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">x</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">></span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p id="index-15">It is often tedious to work with compound statements with a negation in front, and it is a common mathematical pattern to replace such statements with equivalent forms in which the negation has been pushed inward. To facilitate this, mathlib offers a <code class="docutils literal notranslate"><span class="pre">push_neg</span></code> tactic, which restates the goal in this way. The command <code class="docutils literal notranslate"><span class="pre">push_neg</span> <span class="pre">at</span> <span class="pre">h</span></code> restates the hypothesis <code class="docutils literal notranslate"><span class="pre">h</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">¬∀</span> <span class="n">a</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">x</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">></span> <span class="n">a</span><span class="o">)</span> <span class="o">:</span> <span class="n">FnHasUb</span> <span class="n">f</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">push_neg</span> <span class="n">at</span> <span class="n">h</span> <span class="n">exact</span> <span class="n">h</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">FnHasUb</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">x</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">></span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="n">only</span> <span class="o">[</span><span class="n">FnHasUb</span><span class="o">,</span> <span class="n">FnUb</span><span class="o">]</span> <span class="n">at</span> <span class="n">h</span> <span class="n">push_neg</span> <span class="n">at</span> <span class="n">h</span> <span class="n">exact</span> <span class="n">h</span> </pre></div> </div> <p>In the second example, we use Lean’s simplifier to expand the definitions of <code class="docutils literal notranslate"><span class="pre">FnHasUb</span></code> and <code class="docutils literal notranslate"><span class="pre">FnUb</span></code>. (We need to use <code class="docutils literal notranslate"><span class="pre">simp</span></code> rather than <code class="docutils literal notranslate"><span class="pre">rw</span></code> to expand <code class="docutils literal notranslate"><span class="pre">FnUb</span></code>, because it appears in the scope of a quantifier.) You can verify that in the examples above with <code class="docutils literal notranslate"><span class="pre">¬</span> <span class="pre">∃</span> <span class="pre">x,</span> <span class="pre">P</span> <span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">¬</span> <span class="pre">∀</span> <span class="pre">x,</span> <span class="pre">P</span> <span class="pre">x</span></code>, the <code class="docutils literal notranslate"><span class="pre">push_neg</span></code> tactic does the expected thing. Without even knowing how to use the conjunction symbol, you should be able to use <code class="docutils literal notranslate"><span class="pre">push_neg</span></code> to prove the following:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">Monotone</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span> <span class="n">y</span><span class="o">,</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">∧</span> <span class="n">f</span> <span class="n">y</span> <span class="bp"><</span> <span class="n">f</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p id="index-16">Mathlib also has a tactic, <code class="docutils literal notranslate"><span class="pre">contrapose</span></code>, which transforms a goal <code class="docutils literal notranslate"><span class="pre">A</span> <span class="pre">→</span> <span class="pre">B</span></code> to <code class="docutils literal notranslate"><span class="pre">¬</span> <span class="pre">B</span> <span class="pre">→</span> <span class="pre">¬</span> <span class="pre">A</span></code>. Similarly, given a goal of proving <code class="docutils literal notranslate"><span class="pre">B</span></code> from hypothesis <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">:</span> <span class="pre">A</span></code>, <code class="docutils literal notranslate"><span class="pre">contrapose</span> <span class="pre">h</span></code> leaves you with a goal of proving <code class="docutils literal notranslate"><span class="pre">¬</span> <span class="pre">A</span></code> from hypothesis <code class="docutils literal notranslate"><span class="pre">¬</span> <span class="pre">B</span></code>. Using <code class="docutils literal notranslate"><span class="pre">contrapose!</span></code> instead of <code class="docutils literal notranslate"><span class="pre">contrapose</span></code> applies <code class="docutils literal notranslate"><span class="pre">push_neg</span></code> to the goal and the relevant hypothesis as well.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">FnHasUb</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">x</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">></span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">contrapose</span><span class="bp">!</span> <span class="n">h</span> <span class="n">exact</span> <span class="n">h</span> <span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">ε</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">contrapose</span><span class="bp">!</span> <span class="n">h</span> <span class="n">use</span> <span class="n">x</span> <span class="bp">/</span> <span class="mi">2</span> <span class="n">constructor</span> <span class="bp"><;></span> <span class="n">linarith</span> </pre></div> </div> <p>We have not yet explained the <code class="docutils literal notranslate"><span class="pre">constructor</span></code> command or the use of the semicolon after it, but we will do that in the next section.</p> <p>We close this section with the principle of <em>ex falso</em>, which says that anything follows from a contradiction. In Lean, this is represented by <code class="docutils literal notranslate"><span class="pre">False.elim</span></code>, which establishes <code class="docutils literal notranslate"><span class="pre">False</span> <span class="pre">→</span> <span class="pre">P</span></code> for any proposition <code class="docutils literal notranslate"><span class="pre">P</span></code>. This may seem like a strange principle, but it comes up fairly often. We often prove a theorem by splitting on cases, and sometimes we can show that one of the cases is contradictory. In that case, we need to assert that the contradiction establishes the goal so we can move on to the next one. (We will see instances of reasoning by cases in <a class="reference internal" href="#disjunction"><span class="std std-numref">Section 3.5</span></a>.)</p> <p id="index-17">Lean provides a number of ways of closing a goal once a contradiction has been reached.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">></span> <span class="mi">37</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">exfalso</span> <span class="n">apply</span> <span class="n">lt_irrefl</span> <span class="mi">0</span> <span class="n">h</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">></span> <span class="mi">37</span> <span class="o">:=</span> <span class="n">absurd</span> <span class="n">h</span> <span class="o">(</span><span class="n">lt_irrefl</span> <span class="mi">0</span><span class="o">)</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">></span> <span class="mi">37</span> <span class="o">:=</span> <span class="kd">by</span> <span class="k">have</span> <span class="n">h'</span> <span class="o">:</span> <span class="bp">¬</span><span class="mi">0</span> <span class="bp"><</span> <span class="mi">0</span> <span class="o">:=</span> <span class="n">lt_irrefl</span> <span class="mi">0</span> <span class="n">contradiction</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">exfalso</span></code> tactic replaces the current goal with the goal of proving <code class="docutils literal notranslate"><span class="pre">False</span></code>. Given <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">:</span> <span class="pre">P</span></code> and <code class="docutils literal notranslate"><span class="pre">h'</span> <span class="pre">:</span> <span class="pre">¬</span> <span class="pre">P</span></code>, the term <code class="docutils literal notranslate"><span class="pre">absurd</span> <span class="pre">h</span> <span class="pre">h'</span></code> establishes any proposition. Finally, the <code class="docutils literal notranslate"><span class="pre">contradiction</span></code> tactic tries to close a goal by finding a contradiction in the hypotheses, such as a pair of the form <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">:</span> <span class="pre">P</span></code> and <code class="docutils literal notranslate"><span class="pre">h'</span> <span class="pre">:</span> <span class="pre">¬</span> <span class="pre">P</span></code>. Of course, in this example, <code class="docutils literal notranslate"><span class="pre">linarith</span></code> also works.</p> </section> <section id="conjunction-and-bi-implication"> <span id="conjunction-and-biimplication"></span><h2><span class="section-number">3.4. </span>Conjunction and Bi-implication<a class="headerlink" href="#conjunction-and-bi-implication" title="Permalink to this heading"></a></h2> <p id="index-18">You have already seen that the conjunction symbol, <code class="docutils literal notranslate"><span class="pre">∧</span></code>, is used to express “and.” The <code class="docutils literal notranslate"><span class="pre">constructor</span></code> tactic allows you to prove a statement of the form <code class="docutils literal notranslate"><span class="pre">A</span> <span class="pre">∧</span> <span class="pre">B</span></code> by proving <code class="docutils literal notranslate"><span class="pre">A</span></code> and then proving <code class="docutils literal notranslate"><span class="pre">B</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h₀</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span><span class="o">)</span> <span class="o">(</span><span class="n">h₁</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">y</span> <span class="bp">≤</span> <span class="n">x</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp">≠</span> <span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">constructor</span> <span class="bp">·</span> <span class="n">assumption</span> <span class="n">intro</span> <span class="n">h</span> <span class="n">apply</span> <span class="n">h₁</span> <span class="n">rw</span> <span class="o">[</span><span class="n">h</span><span class="o">]</span> </pre></div> </div> <p id="index-19">In this example, the <code class="docutils literal notranslate"><span class="pre">assumption</span></code> tactic tells Lean to find an assumption that will solve the goal. Notice that the final <code class="docutils literal notranslate"><span class="pre">rw</span></code> finishes the goal by applying the reflexivity of <code class="docutils literal notranslate"><span class="pre">≤</span></code>. The following are alternative ways of carrying out the previous examples using the anonymous constructor angle brackets. The first is a slick proof-term version of the previous proof, which drops into tactic mode at the keyword <code class="docutils literal notranslate"><span class="pre">by</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h₀</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span><span class="o">)</span> <span class="o">(</span><span class="n">h₁</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">y</span> <span class="bp">≤</span> <span class="n">x</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp">≠</span> <span class="n">y</span> <span class="o">:=</span> <span class="o">⟨</span><span class="n">h₀</span><span class="o">,</span> <span class="k">fun</span> <span class="n">h</span> <span class="bp">=></span> <span class="n">h₁</span> <span class="o">(</span><span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">h</span><span class="o">])⟩</span> <span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h₀</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span><span class="o">)</span> <span class="o">(</span><span class="n">h₁</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">y</span> <span class="bp">≤</span> <span class="n">x</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp">≠</span> <span class="n">y</span> <span class="o">:=</span> <span class="k">have</span> <span class="n">h</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≠</span> <span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">contrapose</span><span class="bp">!</span> <span class="n">h₁</span> <span class="n">rw</span> <span class="o">[</span><span class="n">h₁</span><span class="o">]</span> <span class="o">⟨</span><span class="n">h₀</span><span class="o">,</span> <span class="n">h</span><span class="o">⟩</span> </pre></div> </div> <p><em>Using</em> a conjunction instead of proving one involves unpacking the proofs of the two parts. You can use the <code class="docutils literal notranslate"><span class="pre">cases</span></code> tactic for that, as well as <code class="docutils literal notranslate"><span class="pre">rcases</span></code>, <code class="docutils literal notranslate"><span class="pre">rintro</span></code>, or a pattern-matching lambda, all in a manner similar to the way they are used with the existential quantifier.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp">≠</span> <span class="n">y</span><span class="o">)</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">y</span> <span class="bp">≤</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">cases'</span> <span class="n">h</span> <span class="k">with</span> <span class="n">h₀</span> <span class="n">h₁</span> <span class="n">contrapose</span><span class="bp">!</span> <span class="n">h₁</span> <span class="n">exact</span> <span class="n">le_antisymm</span> <span class="n">h₀</span> <span class="n">h₁</span> <span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp">≠</span> <span class="n">y</span> <span class="bp">→</span> <span class="bp">¬</span><span class="n">y</span> <span class="bp">≤</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rintro</span> <span class="o">⟨</span><span class="n">h₀</span><span class="o">,</span> <span class="n">h₁</span><span class="o">⟩</span> <span class="n">h'</span> <span class="n">exact</span> <span class="n">h₁</span> <span class="o">(</span><span class="n">le_antisymm</span> <span class="n">h₀</span> <span class="n">h'</span><span class="o">)</span> <span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp">≠</span> <span class="n">y</span> <span class="bp">→</span> <span class="bp">¬</span><span class="n">y</span> <span class="bp">≤</span> <span class="n">x</span> <span class="o">:=</span> <span class="k">fun</span> <span class="o">⟨</span><span class="n">h₀</span><span class="o">,</span> <span class="n">h₁</span><span class="o">⟩</span> <span class="n">h'</span> <span class="bp">=></span> <span class="n">h₁</span> <span class="o">(</span><span class="n">le_antisymm</span> <span class="n">h₀</span> <span class="n">h'</span><span class="o">)</span> </pre></div> </div> <p>In contrast to using an existential quantifier, you can also extract proofs of the two components of a hypothesis <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">:</span> <span class="pre">A</span> <span class="pre">∧</span> <span class="pre">B</span></code> by writing <code class="docutils literal notranslate"><span class="pre">h.left</span></code> and <code class="docutils literal notranslate"><span class="pre">h.right</span></code>, or, equivalently, <code class="docutils literal notranslate"><span class="pre">h.1</span></code> and <code class="docutils literal notranslate"><span class="pre">h.2</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp">≠</span> <span class="n">y</span><span class="o">)</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">y</span> <span class="bp">≤</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">h'</span> <span class="n">apply</span> <span class="n">h.right</span> <span class="n">exact</span> <span class="n">le_antisymm</span> <span class="n">h.left</span> <span class="n">h'</span> <span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp">≠</span> <span class="n">y</span><span class="o">)</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">y</span> <span class="bp">≤</span> <span class="n">x</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">h'</span> <span class="bp">=></span> <span class="n">h.right</span> <span class="o">(</span><span class="n">le_antisymm</span> <span class="n">h.left</span> <span class="n">h'</span><span class="o">)</span> </pre></div> </div> <p>Try using these techniques to come up with various ways of proving of the following:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">∣</span> <span class="n">n</span> <span class="bp">∧</span> <span class="n">m</span> <span class="bp">≠</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">∣</span> <span class="n">n</span> <span class="bp">∧</span> <span class="bp">¬</span><span class="n">n</span> <span class="bp">∣</span> <span class="n">m</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>You can nest uses of <code class="docutils literal notranslate"><span class="pre">∃</span></code> and <code class="docutils literal notranslate"><span class="pre">∧</span></code> with anonymous constructors, <code class="docutils literal notranslate"><span class="pre">rintro</span></code>, and <code class="docutils literal notranslate"><span class="pre">rcases</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">,</span> <span class="mi">2</span> <span class="bp"><</span> <span class="n">x</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp"><</span> <span class="mi">4</span> <span class="o">:=</span> <span class="o">⟨</span><span class="mi">5</span> <span class="bp">/</span> <span class="mi">2</span><span class="o">,</span> <span class="kd">by</span> <span class="n">norm_num</span><span class="o">,</span> <span class="kd">by</span> <span class="n">norm_num</span><span class="o">⟩</span> <span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="bp">∃</span> <span class="n">z</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">,</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">z</span> <span class="bp">∧</span> <span class="n">z</span> <span class="bp"><</span> <span class="n">y</span><span class="o">)</span> <span class="bp">→</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rintro</span> <span class="o">⟨</span><span class="n">z</span><span class="o">,</span> <span class="n">xltz</span><span class="o">,</span> <span class="n">zlty</span><span class="o">⟩</span> <span class="n">exact</span> <span class="n">lt_trans</span> <span class="n">xltz</span> <span class="n">zlty</span> <span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="bp">∃</span> <span class="n">z</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">,</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">z</span> <span class="bp">∧</span> <span class="n">z</span> <span class="bp"><</span> <span class="n">y</span><span class="o">)</span> <span class="bp">→</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">y</span> <span class="o">:=</span> <span class="k">fun</span> <span class="o">⟨</span><span class="n">z</span><span class="o">,</span> <span class="n">xltz</span><span class="o">,</span> <span class="n">zlty</span><span class="o">⟩</span> <span class="bp">=></span> <span class="n">lt_trans</span> <span class="n">xltz</span> <span class="n">zlty</span> </pre></div> </div> <p>You can also use the <code class="docutils literal notranslate"><span class="pre">use</span></code> tactic:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">,</span> <span class="mi">2</span> <span class="bp"><</span> <span class="n">x</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp"><</span> <span class="mi">4</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">use</span> <span class="mi">5</span> <span class="bp">/</span> <span class="mi">2</span> <span class="n">constructor</span> <span class="bp"><;></span> <span class="n">norm_num</span> <span class="kd">example</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">,</span> <span class="mi">4</span> <span class="bp"><</span> <span class="n">m</span> <span class="bp">∧</span> <span class="n">m</span> <span class="bp"><</span> <span class="n">n</span> <span class="bp">∧</span> <span class="n">n</span> <span class="bp"><</span> <span class="mi">10</span> <span class="bp">∧</span> <span class="n">Nat.Prime</span> <span class="n">m</span> <span class="bp">∧</span> <span class="n">Nat.Prime</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">use</span> <span class="mi">5</span> <span class="n">use</span> <span class="mi">7</span> <span class="n">norm_num</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp">≠</span> <span class="n">y</span> <span class="bp">→</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">∧</span> <span class="bp">¬</span><span class="n">y</span> <span class="bp">≤</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rintro</span> <span class="o">⟨</span><span class="n">h₀</span><span class="o">,</span> <span class="n">h₁</span><span class="o">⟩</span> <span class="n">use</span> <span class="n">h₀</span> <span class="n">exact</span> <span class="k">fun</span> <span class="n">h'</span> <span class="bp">=></span> <span class="n">h₁</span> <span class="o">(</span><span class="n">le_antisymm</span> <span class="n">h₀</span> <span class="n">h'</span><span class="o">)</span> </pre></div> </div> <p>In the first example, the semicolon after the <code class="docutils literal notranslate"><span class="pre">constructor</span></code> command tells Lean to use the <code class="docutils literal notranslate"><span class="pre">norm_num</span></code> tactic on both of the goals that result.</p> <p>In Lean, <code class="docutils literal notranslate"><span class="pre">A</span> <span class="pre">↔</span> <span class="pre">B</span></code> is <em>not</em> defined to be <code class="docutils literal notranslate"><span class="pre">(A</span> <span class="pre">→</span> <span class="pre">B)</span> <span class="pre">∧</span> <span class="pre">(B</span> <span class="pre">→</span> <span class="pre">A)</span></code>, but it could have been, and it behaves roughly the same way. You have already seen that you can write <code class="docutils literal notranslate"><span class="pre">h.mp</span></code> and <code class="docutils literal notranslate"><span class="pre">h.mpr</span></code> or <code class="docutils literal notranslate"><span class="pre">h.1</span></code> and <code class="docutils literal notranslate"><span class="pre">h.2</span></code> for the two directions of <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">:</span> <span class="pre">A</span> <span class="pre">↔</span> <span class="pre">B</span></code>. You can also use <code class="docutils literal notranslate"><span class="pre">cases</span></code> and friends. To prove an if-and-only-if statement, you can uses <code class="docutils literal notranslate"><span class="pre">constructor</span></code> or angle brackets, just as you would if you were proving a conjunction.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span><span class="o">)</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">y</span> <span class="bp">≤</span> <span class="n">x</span> <span class="bp">↔</span> <span class="n">x</span> <span class="bp">≠</span> <span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">constructor</span> <span class="bp">·</span> <span class="n">contrapose</span><span class="bp">!</span> <span class="n">rintro</span> <span class="n">rfl</span> <span class="n">rfl</span> <span class="n">contrapose</span><span class="bp">!</span> <span class="n">exact</span> <span class="n">le_antisymm</span> <span class="n">h</span> <span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span><span class="o">)</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">y</span> <span class="bp">≤</span> <span class="n">x</span> <span class="bp">↔</span> <span class="n">x</span> <span class="bp">≠</span> <span class="n">y</span> <span class="o">:=</span> <span class="o">⟨</span><span class="k">fun</span> <span class="n">h₀</span> <span class="n">h₁</span> <span class="bp">=></span> <span class="n">h₀</span> <span class="o">(</span><span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">h₁</span><span class="o">]),</span> <span class="k">fun</span> <span class="n">h₀</span> <span class="n">h₁</span> <span class="bp">=></span> <span class="n">h₀</span> <span class="o">(</span><span class="n">le_antisymm</span> <span class="n">h</span> <span class="n">h₁</span><span class="o">)⟩</span> </pre></div> </div> <p>The last proof term is inscrutable. Remember that you can use underscores while writing an expression like that to see what Lean expects.</p> <p>Try out the various techniques and gadgets you have just seen in order to prove the following:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">∧</span> <span class="bp">¬</span><span class="n">y</span> <span class="bp">≤</span> <span class="n">x</span> <span class="bp">↔</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp">≠</span> <span class="n">y</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>For a more interesting exercise, show that for any two real numbers <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code>, <code class="docutils literal notranslate"><span class="pre">x^2</span> <span class="pre">+</span> <span class="pre">y^2</span> <span class="pre">=</span> <span class="pre">0</span></code> if and only if <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">=</span> <span class="pre">0</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span> <span class="pre">=</span> <span class="pre">0</span></code>. We suggest proving an auxiliary lemma using <code class="docutils literal notranslate"><span class="pre">linarith</span></code>, <code class="docutils literal notranslate"><span class="pre">pow_two_nonneg</span></code>, and <code class="docutils literal notranslate"><span class="pre">pow_eq_zero</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">aux</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="n">y</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="k">have</span> <span class="n">h'</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="n">pow_eq_zero</span> <span class="n">h'</span> <span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="n">y</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">=</span> <span class="mi">0</span> <span class="bp">↔</span> <span class="n">x</span> <span class="bp">=</span> <span class="mi">0</span> <span class="bp">∧</span> <span class="n">y</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>In Lean, bi-implication leads a double-life. You can treat it like a conjunction and use its two parts separately. But Lean also knows that it is a reflexive, symmetric, and transitive relation between propositions, and you can also use it with <code class="docutils literal notranslate"><span class="pre">calc</span></code> and <code class="docutils literal notranslate"><span class="pre">rw</span></code>. It is often convenient to rewrite a statement to an equivalent one. In the next example, we use <code class="docutils literal notranslate"><span class="pre">abs_lt</span></code> to replace an expression of the form <code class="docutils literal notranslate"><span class="pre">abs</span> <span class="pre">x</span> <span class="pre"><</span> <span class="pre">y</span></code> by the equivalent expression <code class="docutils literal notranslate"><span class="pre">-</span> <span class="pre">y</span> <span class="pre"><</span> <span class="pre">x</span> <span class="pre">∧</span> <span class="pre">x</span> <span class="pre"><</span> <span class="pre">y</span></code>, and in the one after that we use <code class="docutils literal notranslate"><span class="pre">Nat.dvd_gcd_iff</span></code> to replace an expression of the form <code class="docutils literal notranslate"><span class="pre">m</span> <span class="pre">∣</span> <span class="pre">Nat.gcd</span> <span class="pre">n</span> <span class="pre">k</span></code> by the equivalent expression <code class="docutils literal notranslate"><span class="pre">m</span> <span class="pre">∣</span> <span class="pre">n</span> <span class="pre">∧</span> <span class="pre">m</span> <span class="pre">∣</span> <span class="pre">k</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">abs</span> <span class="o">(</span><span class="n">x</span> <span class="bp">+</span> <span class="mi">3</span><span class="o">)</span> <span class="bp"><</span> <span class="mi">5</span> <span class="bp">→</span> <span class="bp">-</span><span class="mi">8</span> <span class="bp"><</span> <span class="n">x</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp"><</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">abs_lt</span><span class="o">]</span> <span class="n">intro</span> <span class="n">h</span> <span class="n">constructor</span> <span class="bp"><;></span> <span class="n">linarith</span> <span class="kd">example</span> <span class="o">:</span> <span class="mi">3</span> <span class="bp">∣</span> <span class="n">Nat.gcd</span> <span class="mi">6</span> <span class="mi">15</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">Nat.dvd_gcd_iff</span><span class="o">]</span> <span class="n">constructor</span> <span class="bp"><;></span> <span class="n">norm_num</span> </pre></div> </div> <p>See if you can use <code class="docutils literal notranslate"><span class="pre">rw</span></code> with the theorem below to provide a short proof that negation is not a nondecreasing function. (Note that <code class="docutils literal notranslate"><span class="pre">push_neg</span></code> won’t unfold definitions for you, so the <code class="docutils literal notranslate"><span class="pre">rw</span> <span class="pre">monotone</span></code> in the proof of the theorem is needed.)</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">not_monotone_iff</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">Monotone</span> <span class="n">f</span> <span class="bp">↔</span> <span class="bp">∃</span> <span class="n">x</span> <span class="n">y</span><span class="o">,</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">y</span> <span class="bp">∧</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">></span> <span class="n">f</span> <span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">Monotone</span><span class="o">]</span> <span class="n">push_neg</span> <span class="n">rfl</span> <span class="kd">example</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">Monotone</span> <span class="k">fun</span> <span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">=></span> <span class="bp">-</span><span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>The remaining exercises in this section are designed to give you some more practice with conjunction and bi-implication. Remember that a <em>partial order</em> is a binary relation that is transitive, reflexive, and antisymmetric. An even weaker notion sometimes arises: a <em>preorder</em> is just a reflexive, transitive relation. For any pre-order <code class="docutils literal notranslate"><span class="pre">≤</span></code>, Lean axiomatizes the associated strict pre-order by <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre"><</span> <span class="pre">b</span> <span class="pre">↔</span> <span class="pre">a</span> <span class="pre">≤</span> <span class="pre">b</span> <span class="pre">∧</span> <span class="pre">¬</span> <span class="pre">b</span> <span class="pre">≤</span> <span class="pre">a</span></code>. Show that if <code class="docutils literal notranslate"><span class="pre">≤</span></code> is a partial order, then <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre"><</span> <span class="pre">b</span></code> is equivalent to <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">≤</span> <span class="pre">b</span> <span class="pre">∧</span> <span class="pre">a</span> <span class="pre">≠</span> <span class="pre">b</span></code>:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">PartialOrder</span> <span class="n">α</span><span class="o">]</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">b</span> <span class="bp">↔</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">∧</span> <span class="n">a</span> <span class="bp">≠</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">lt_iff_le_not_le</span><span class="o">]</span> <span class="gr">sorry</span> </pre></div> </div> <p id="index-20">Beyond logical operations, you should not need anything more than <code class="docutils literal notranslate"><span class="pre">le_refl</span></code> and <code class="docutils literal notranslate"><span class="pre">le_antisymm</span></code>. Then show that even in the case where <code class="docutils literal notranslate"><span class="pre">≤</span></code> is only assumed to be a preorder, we can prove that the strict order is irreflexive and transitive. You do not need anything more than <code class="docutils literal notranslate"><span class="pre">le_refl</span></code> and <code class="docutils literal notranslate"><span class="pre">le_trans</span></code>. In the second example, for convenience, we use the simplifier rather than <code class="docutils literal notranslate"><span class="pre">rw</span></code> to express <code class="docutils literal notranslate"><span class="pre"><</span></code> in terms of <code class="docutils literal notranslate"><span class="pre">≤</span></code> and <code class="docutils literal notranslate"><span class="pre">¬</span></code>. We will come back to the simplifier later, but here we are only relying on the fact that it will use the indicated lemma repeatedly, even if it needs to be instantiated to different values.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">Preorder</span> <span class="n">α</span><span class="o">]</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="kd">example</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">a</span> <span class="bp"><</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">lt_iff_le_not_le</span><span class="o">]</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">b</span> <span class="bp">→</span> <span class="n">b</span> <span class="bp"><</span> <span class="n">c</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">c</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="n">only</span> <span class="o">[</span><span class="n">lt_iff_le_not_le</span><span class="o">]</span> <span class="gr">sorry</span> </pre></div> </div> </section> <section id="disjunction"> <span id="id5"></span><h2><span class="section-number">3.5. </span>Disjunction<a class="headerlink" href="#disjunction" title="Permalink to this heading"></a></h2> <p id="index-21">The canonical way to prove a disjunction <code class="docutils literal notranslate"><span class="pre">A</span> <span class="pre">∨</span> <span class="pre">B</span></code> is to prove <code class="docutils literal notranslate"><span class="pre">A</span></code> or to prove <code class="docutils literal notranslate"><span class="pre">B</span></code>. The <code class="docutils literal notranslate"><span class="pre">left</span></code> tactic chooses <code class="docutils literal notranslate"><span class="pre">A</span></code>, and the <code class="docutils literal notranslate"><span class="pre">right</span></code> tactic chooses <code class="docutils literal notranslate"><span class="pre">B</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">y</span> <span class="bp">></span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span><span class="o">)</span> <span class="o">:</span> <span class="n">y</span> <span class="bp">></span> <span class="mi">0</span> <span class="bp">∨</span> <span class="n">y</span> <span class="bp"><</span> <span class="bp">-</span><span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">left</span> <span class="n">linarith</span> <span class="o">[</span><span class="n">pow_two_nonneg</span> <span class="n">x</span><span class="o">]</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">-</span><span class="n">y</span> <span class="bp">></span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="o">:</span> <span class="n">y</span> <span class="bp">></span> <span class="mi">0</span> <span class="bp">∨</span> <span class="n">y</span> <span class="bp"><</span> <span class="bp">-</span><span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">right</span> <span class="n">linarith</span> <span class="o">[</span><span class="n">pow_two_nonneg</span> <span class="n">x</span><span class="o">]</span> </pre></div> </div> <p>We cannot use an anonymous constructor to construct a proof of an “or” because Lean would have to guess which disjunct we are trying to prove. When we write proof terms we can use <code class="docutils literal notranslate"><span class="pre">Or.inl</span></code> and <code class="docutils literal notranslate"><span class="pre">Or.inr</span></code> instead to make the choice explicitly. Here, <code class="docutils literal notranslate"><span class="pre">inl</span></code> is short for “introduction left” and <code class="docutils literal notranslate"><span class="pre">inr</span></code> is short for “introduction right.”</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">y</span> <span class="bp">></span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="n">y</span> <span class="bp">></span> <span class="mi">0</span> <span class="bp">∨</span> <span class="n">y</span> <span class="bp"><</span> <span class="bp">-</span><span class="mi">1</span> <span class="o">:=</span> <span class="n">Or.inl</span> <span class="n">h</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">y</span> <span class="bp"><</span> <span class="bp">-</span><span class="mi">1</span><span class="o">)</span> <span class="o">:</span> <span class="n">y</span> <span class="bp">></span> <span class="mi">0</span> <span class="bp">∨</span> <span class="n">y</span> <span class="bp"><</span> <span class="bp">-</span><span class="mi">1</span> <span class="o">:=</span> <span class="n">Or.inr</span> <span class="n">h</span> </pre></div> </div> <p>It may seem strange to prove a disjunction by proving one side or the other. In practice, which case holds usually depends a case distinction that is implicit or explicit in the assumptions and the data. The <code class="docutils literal notranslate"><span class="pre">cases</span></code> tactic allows us to make use of a hypothesis of the form <code class="docutils literal notranslate"><span class="pre">A</span> <span class="pre">∨</span> <span class="pre">B</span></code>. In contrast to the use of <code class="docutils literal notranslate"><span class="pre">cases</span></code> with conjunction or an existential quantifier, here the <code class="docutils literal notranslate"><span class="pre">cases</span></code> tactic produces <em>two</em> goals. Both have the same conclusion, but in the first case, <code class="docutils literal notranslate"><span class="pre">A</span></code> is assumed to be true, and in the second case, <code class="docutils literal notranslate"><span class="pre">B</span></code> is assumed to be true. In other words, as the name suggests, the <code class="docutils literal notranslate"><span class="pre">cases</span></code> tactic carries out a proof by cases. As usual, we can tell Lean what names to use for the hypotheses. In the next example, we tell Lean to use the name <code class="docutils literal notranslate"><span class="pre">h</span></code> on each branch.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">abs</span> <span class="n">y</span> <span class="bp">→</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">y</span> <span class="bp">∨</span> <span class="n">x</span> <span class="bp"><</span> <span class="bp">-</span><span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">cases'</span> <span class="n">le_or_gt</span> <span class="mi">0</span> <span class="n">y</span> <span class="k">with</span> <span class="n">h</span> <span class="n">h</span> <span class="bp">·</span> <span class="n">rw</span> <span class="o">[</span><span class="n">abs_of_nonneg</span> <span class="n">h</span><span class="o">]</span> <span class="n">intro</span> <span class="n">h</span> <span class="n">left</span> <span class="n">exact</span> <span class="n">h</span> <span class="n">rw</span> <span class="o">[</span><span class="n">abs_of_neg</span> <span class="n">h</span><span class="o">]</span> <span class="n">intro</span> <span class="n">h</span><span class="bp">;</span> <span class="n">right</span><span class="bp">;</span> <span class="n">exact</span> <span class="n">h</span> </pre></div> </div> <p>The absolute value function is defined in such a way that we can immediately prove that <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">≥</span> <span class="pre">0</span></code> implies <code class="docutils literal notranslate"><span class="pre">abs</span> <span class="pre">x</span> <span class="pre">=</span> <span class="pre">x</span></code> (this is the theorem <code class="docutils literal notranslate"><span class="pre">abs_of_nonneg</span></code>) and <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre"><</span> <span class="pre">0</span></code> implies <code class="docutils literal notranslate"><span class="pre">abs</span> <span class="pre">x</span> <span class="pre">=</span> <span class="pre">-x</span></code> (this is <code class="docutils literal notranslate"><span class="pre">abs_of_neg</span></code>). The expression <code class="docutils literal notranslate"><span class="pre">le_or_gt</span> <span class="pre">0</span> <span class="pre">x</span></code> establishes <code class="docutils literal notranslate"><span class="pre">0</span> <span class="pre">≤</span> <span class="pre">x</span> <span class="pre">∨</span> <span class="pre">x</span> <span class="pre"><</span> <span class="pre">0</span></code>, allowing us to split on those two cases. Try proving the triangle inequality using the two first two theorems in the next snippet. They are given the same names they have in mathlib.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">namespace</span> <span class="n">MyAbs</span> <span class="kd">theorem</span> <span class="n">le_abs_self</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">abs</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">neg_le_abs_self</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="bp">-</span><span class="n">x</span> <span class="bp">≤</span> <span class="n">abs</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">abs_add</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">abs</span> <span class="o">(</span><span class="n">x</span> <span class="bp">+</span> <span class="n">y</span><span class="o">)</span> <span class="bp">≤</span> <span class="n">abs</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">abs</span> <span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>In case you enjoyed these (pun intended) and you want more practice with disjunction, try these.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">lt_abs</span> <span class="o">:</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">abs</span> <span class="n">y</span> <span class="bp">↔</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">y</span> <span class="bp">∨</span> <span class="n">x</span> <span class="bp"><</span> <span class="bp">-</span><span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">abs_lt</span> <span class="o">:</span> <span class="n">abs</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">y</span> <span class="bp">↔</span> <span class="bp">-</span><span class="n">y</span> <span class="bp"><</span> <span class="n">x</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>You can also use <code class="docutils literal notranslate"><span class="pre">rcases</span></code> and <code class="docutils literal notranslate"><span class="pre">rintro</span></code> with disjunctions. When these result in a genuine case split with multiple goals, the patterns for each new goal are separated by a vertical bar.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">≠</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp"><</span> <span class="mi">0</span> <span class="bp">∨</span> <span class="n">x</span> <span class="bp">></span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rcases</span> <span class="n">lt_trichotomy</span> <span class="n">x</span> <span class="mi">0</span> <span class="k">with</span> <span class="o">(</span><span class="n">xlt</span> <span class="bp">|</span> <span class="n">xeq</span> <span class="bp">|</span> <span class="n">xgt</span><span class="o">)</span> <span class="bp">·</span> <span class="n">left</span> <span class="n">exact</span> <span class="n">xlt</span> <span class="bp">·</span> <span class="n">contradiction</span> <span class="n">right</span><span class="bp">;</span> <span class="n">exact</span> <span class="n">xgt</span> </pre></div> </div> <p>You can still nest patterns and use the <code class="docutils literal notranslate"><span class="pre">rfl</span></code> keyword to substitute equations:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">m</span> <span class="n">n</span> <span class="n">k</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">∣</span> <span class="n">n</span> <span class="bp">∨</span> <span class="n">m</span> <span class="bp">∣</span> <span class="n">k</span><span class="o">)</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">∣</span> <span class="n">n</span> <span class="bp">*</span> <span class="n">k</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rcases</span> <span class="n">h</span> <span class="k">with</span> <span class="o">(⟨</span><span class="n">a</span><span class="o">,</span> <span class="n">rfl</span><span class="o">⟩</span> <span class="bp">|</span> <span class="o">⟨</span><span class="n">b</span><span class="o">,</span> <span class="n">rfl</span><span class="o">⟩)</span> <span class="bp">·</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mul_assoc</span><span class="o">]</span> <span class="n">apply</span> <span class="n">dvd_mul_right</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mul_comm</span><span class="o">,</span> <span class="n">mul_assoc</span><span class="o">]</span> <span class="n">apply</span> <span class="n">dvd_mul_right</span> </pre></div> </div> <p>See if you can prove the following with a single (long) line. Use <code class="docutils literal notranslate"><span class="pre">rcases</span></code> to unpack the hypotheses and split on cases, and use a semicolon and <code class="docutils literal notranslate"><span class="pre">linarith</span></code> to solve each branch.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">z</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span> <span class="n">y</span><span class="o">,</span> <span class="n">z</span> <span class="bp">=</span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="n">y</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">∨</span> <span class="n">z</span> <span class="bp">=</span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="n">y</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="o">:</span> <span class="n">z</span> <span class="bp">≥</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>On the real numbers, an equation <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">*</span> <span class="pre">y</span> <span class="pre">=</span> <span class="pre">0</span></code> tells us that <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">=</span> <span class="pre">0</span></code> or <code class="docutils literal notranslate"><span class="pre">y</span> <span class="pre">=</span> <span class="pre">0</span></code>. In mathlib, this fact is known as <code class="docutils literal notranslate"><span class="pre">eq_zero_or_eq_zero_of_mul_eq_zero</span></code>, and it is another nice example of how a disjunction can arise. See if you can use it to prove the following:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">=</span> <span class="mi">1</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">=</span> <span class="mi">1</span> <span class="bp">∨</span> <span class="n">x</span> <span class="bp">=</span> <span class="bp">-</span><span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">=</span> <span class="n">y</span> <span class="bp">^</span> <span class="mi">2</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">y</span> <span class="bp">∨</span> <span class="n">x</span> <span class="bp">=</span> <span class="bp">-</span><span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Remember that you can use the <code class="docutils literal notranslate"><span class="pre">ring</span></code> tactic to help with calculations.</p> <p>In an arbitrary ring <span class="math notranslate nohighlight">\(R\)</span>, an element <span class="math notranslate nohighlight">\(x\)</span> such that <span class="math notranslate nohighlight">\(x y = 0\)</span> for some nonzero <span class="math notranslate nohighlight">\(y\)</span> is called a <em>left zero divisor</em>, an element <span class="math notranslate nohighlight">\(x\)</span> such that <span class="math notranslate nohighlight">\(y x = 0\)</span> for some nonzero <span class="math notranslate nohighlight">\(y\)</span> is called a <em>right zero divisor</em>, and an element that is either a left or right zero divisor is called simply a <em>zero divisor</em>. The theorem <code class="docutils literal notranslate"><span class="pre">eq_zero_or_eq_zero_of_mul_eq_zero</span></code> says that the real numbers have no nontrivial zero divisors. A commutative ring with this property is called an <em>integral domain</em>. Your proofs of the two theorems above should work equally well in any integral domain:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">R</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">CommRing</span> <span class="n">R</span><span class="o">]</span> <span class="o">[</span><span class="n">IsDomain</span> <span class="n">R</span><span class="o">]</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">=</span> <span class="mi">1</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">=</span> <span class="mi">1</span> <span class="bp">∨</span> <span class="n">x</span> <span class="bp">=</span> <span class="bp">-</span><span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">=</span> <span class="n">y</span> <span class="bp">^</span> <span class="mi">2</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">y</span> <span class="bp">∨</span> <span class="n">x</span> <span class="bp">=</span> <span class="bp">-</span><span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>In fact, if you are careful, you can prove the first theorem without using commutativity of multiplication. In that case, it suffices to assume that <code class="docutils literal notranslate"><span class="pre">R</span></code> is a <code class="docutils literal notranslate"><span class="pre">Ring</span></code> instead of an <code class="docutils literal notranslate"><span class="pre">CommRing</span></code>.</p> <p id="index-22">Sometimes in a proof we want to split on cases depending on whether some statement is true or not. For any proposition <code class="docutils literal notranslate"><span class="pre">P</span></code>, we can use <code class="docutils literal notranslate"><span class="pre">em</span> <span class="pre">P</span> <span class="pre">:</span> <span class="pre">P</span> <span class="pre">∨</span> <span class="pre">¬</span> <span class="pre">P</span></code>. The name <code class="docutils literal notranslate"><span class="pre">em</span></code> is short for “excluded middle.”</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">P</span> <span class="o">:</span> <span class="kt">Prop</span><span class="o">)</span> <span class="o">:</span> <span class="bp">¬¬</span><span class="n">P</span> <span class="bp">→</span> <span class="n">P</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">h</span> <span class="n">cases</span> <span class="n">em</span> <span class="n">P</span> <span class="bp">·</span> <span class="n">assumption</span> <span class="n">contradiction</span> </pre></div> </div> <p id="index-23">Alternatively, you can use the <code class="docutils literal notranslate"><span class="pre">by_cases</span></code> tactic.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">P</span> <span class="o">:</span> <span class="kt">Prop</span><span class="o">)</span> <span class="o">:</span> <span class="bp">¬¬</span><span class="n">P</span> <span class="bp">→</span> <span class="n">P</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">h</span> <span class="n">by_cases</span> <span class="n">h'</span> <span class="o">:</span> <span class="n">P</span> <span class="bp">·</span> <span class="n">assumption</span> <span class="n">contradiction</span> </pre></div> </div> <p>Notice that the <code class="docutils literal notranslate"><span class="pre">by_cases</span></code> tactic lets you specify a label for the hypothesis that is introduced in each branch, in this case, <code class="docutils literal notranslate"><span class="pre">h'</span> <span class="pre">:</span> <span class="pre">P</span></code> in one and <code class="docutils literal notranslate"><span class="pre">h'</span> <span class="pre">:</span> <span class="pre">¬</span> <span class="pre">P</span></code> in the other. If you leave out the label, Lean uses <code class="docutils literal notranslate"><span class="pre">h</span></code> by default. Try proving the following equivalence, using <code class="docutils literal notranslate"><span class="pre">by_cases</span></code> to establish one direction.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">P</span> <span class="n">Q</span> <span class="o">:</span> <span class="kt">Prop</span><span class="o">)</span> <span class="o">:</span> <span class="n">P</span> <span class="bp">→</span> <span class="n">Q</span> <span class="bp">↔</span> <span class="bp">¬</span><span class="n">P</span> <span class="bp">∨</span> <span class="n">Q</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> </section> <section id="sequences-and-convergence"> <span id="id6"></span><h2><span class="section-number">3.6. </span>Sequences and Convergence<a class="headerlink" href="#sequences-and-convergence" title="Permalink to this heading"></a></h2> <p>We now have enough skills at our disposal to do some real mathematics. In Lean, we can represent a sequence <span class="math notranslate nohighlight">\(s_0, s_1, s_2, \ldots\)</span> of real numbers as a function <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">:</span> <span class="pre">ℕ</span> <span class="pre">→</span> <span class="pre">ℝ</span></code>. Such a sequence is said to <em>converge</em> to a number <span class="math notranslate nohighlight">\(a\)</span> if for every <span class="math notranslate nohighlight">\(\varepsilon > 0\)</span> there is a point beyond which the sequence remains within <span class="math notranslate nohighlight">\(\varepsilon\)</span> of <span class="math notranslate nohighlight">\(a\)</span>, that is, there is a number <span class="math notranslate nohighlight">\(N\)</span> such that for every <span class="math notranslate nohighlight">\(n \ge N\)</span>, <span class="math notranslate nohighlight">\(| s_n - a | < \varepsilon\)</span>. In Lean, we can render this as follows:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">ConvergesTo</span> <span class="o">(</span><span class="n">s</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:=</span> <span class="bp">∀</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">N</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">n</span> <span class="bp">≥</span> <span class="n">N</span><span class="o">,</span> <span class="n">abs</span> <span class="o">(</span><span class="n">s</span> <span class="n">n</span> <span class="bp">-</span> <span class="n">a</span><span class="o">)</span> <span class="bp"><</span> <span class="n">ε</span> </pre></div> </div> <p>The notation <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">ε</span> <span class="pre">></span> <span class="pre">0,</span> <span class="pre">...</span></code> is a convenient abbreviation for <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">ε,</span> <span class="pre">ε</span> <span class="pre">></span> <span class="pre">0</span> <span class="pre">→</span> <span class="pre">...</span></code>, and, similarly, <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">n</span> <span class="pre">≥</span> <span class="pre">N,</span> <span class="pre">...</span></code> abbreviates <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">n,</span> <span class="pre">n</span> <span class="pre">≥</span> <span class="pre">N</span> <span class="pre">→</span>  <span class="pre">...</span></code>. And remember that <code class="docutils literal notranslate"><span class="pre">ε</span> <span class="pre">></span> <span class="pre">0</span></code>, in turn, is defined as <code class="docutils literal notranslate"><span class="pre">0</span> <span class="pre"><</span> <span class="pre">ε</span></code>, and <code class="docutils literal notranslate"><span class="pre">n</span> <span class="pre">≥</span> <span class="pre">N</span></code> is defined as <code class="docutils literal notranslate"><span class="pre">N</span> <span class="pre">≤</span> <span class="pre">n</span></code>.</p> <p id="index-24">In this section, we’ll establish some properties of convergence. But first, we will discuss three tactics for working with equality that will prove useful. The first, the <code class="docutils literal notranslate"><span class="pre">ext</span></code> tactic, gives us a way of proving that two functions are equal. Let <span class="math notranslate nohighlight">\(f(x) = x + 1\)</span> and <span class="math notranslate nohighlight">\(g(x) = 1 + x\)</span> be functions from reals to reals. Then, of course, <span class="math notranslate nohighlight">\(f = g\)</span>, because they return the same value for every <span class="math notranslate nohighlight">\(x\)</span>. The <code class="docutils literal notranslate"><span class="pre">ext</span></code> tactic enables us to prove an equation between functions by proving that their values are the same at all the values of their arguments.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="k">fun</span> <span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">=></span> <span class="o">(</span><span class="n">x</span> <span class="bp">+</span> <span class="n">y</span><span class="o">)</span> <span class="bp">^</span> <span class="mi">2</span><span class="o">)</span> <span class="bp">=</span> <span class="k">fun</span> <span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">=></span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">x</span> <span class="bp">*</span> <span class="n">y</span> <span class="bp">+</span> <span class="n">y</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ext</span> <span class="n">ring</span> </pre></div> </div> <p id="index-25">We’ll see later that <code class="docutils literal notranslate"><span class="pre">ext</span></code> is actually more general, and also one can specify the name of the variables that appear. For instance you can try to replace <code class="docutils literal notranslate"><span class="pre">ext</span></code> with <code class="docutils literal notranslate"><span class="pre">ext</span> <span class="pre">u</span> <span class="pre">v</span></code> in the above proof. The second tactic, the <code class="docutils literal notranslate"><span class="pre">congr</span></code> tactic, allows us to prove an equation between two expressions by reconciling the parts that are different:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">abs</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">abs</span> <span class="o">(</span><span class="n">a</span> <span class="bp">-</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">congr</span> <span class="n">ring</span> </pre></div> </div> <p>Here the <code class="docutils literal notranslate"><span class="pre">congr</span></code> tactic peels off the <code class="docutils literal notranslate"><span class="pre">abs</span></code> on each side, leaving us to prove <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">=</span> <span class="pre">a</span> <span class="pre">-</span> <span class="pre">b</span> <span class="pre">+</span> <span class="pre">b</span></code>.</p> <p id="index-26">Finally, the <code class="docutils literal notranslate"><span class="pre">convert</span></code> tactic is used to apply a theorem to a goal when the conclusion of the theorem doesn’t quite match. For example, suppose we want to prove <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre"><</span> <span class="pre">a</span> <span class="pre">*</span> <span class="pre">a</span></code> from <code class="docutils literal notranslate"><span class="pre">1</span> <span class="pre"><</span> <span class="pre">a</span></code>. A theorem in the library, <code class="docutils literal notranslate"><span class="pre">mul_lt_mul_right</span></code>, will let us prove <code class="docutils literal notranslate"><span class="pre">1</span> <span class="pre">*</span> <span class="pre">a</span> <span class="pre"><</span> <span class="pre">a</span> <span class="pre">*</span> <span class="pre">a</span></code>. One possibility is to work backwards and rewrite the goal so that it has that form. Instead, the <code class="docutils literal notranslate"><span class="pre">convert</span></code> tactic lets us apply the theorem as it is, and leaves us with the task of proving the equations that are needed to make the goal match.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">a</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="mi">1</span> <span class="bp"><</span> <span class="n">a</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">convert</span><span class="o">(</span><span class="n">mul_lt_mul_right</span> <span class="n">_</span><span class="o">)</span><span class="bp">.</span><span class="mi">2</span> <span class="n">h</span> <span class="bp">·</span> <span class="n">rw</span> <span class="o">[</span><span class="n">one_mul</span><span class="o">]</span> <span class="n">exact</span> <span class="n">lt_trans</span> <span class="n">zero_lt_one</span> <span class="n">h</span> </pre></div> </div> <p>This example illustrates another useful trick: when we apply an expression with an underscore and Lean can’t fill it in for us automatically, it simply leaves it for us as another goal.</p> <p>The following shows that any constant sequence <span class="math notranslate nohighlight">\(a, a, a, \ldots\)</span> converges.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">convergesTo_const</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">ConvergesTo</span> <span class="o">(</span><span class="k">fun</span> <span class="n">x</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">=></span> <span class="n">a</span><span class="o">)</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">ε</span> <span class="n">εpos</span> <span class="n">use</span> <span class="mi">0</span> <span class="n">intro</span> <span class="n">n</span> <span class="n">nge</span><span class="bp">;</span> <span class="n">dsimp</span> <span class="n">rw</span> <span class="o">[</span><span class="n">sub_self</span><span class="o">,</span> <span class="n">abs_zero</span><span class="o">]</span> <span class="n">apply</span> <span class="n">εpos</span> </pre></div> </div> <p>Lean has a tactic, <code class="docutils literal notranslate"><span class="pre">simp</span></code>, which can often save you the trouble of carrying out steps like <code class="docutils literal notranslate"><span class="pre">rw</span> <span class="pre">[sub_self,</span> <span class="pre">abs_zero]</span></code> by hand. We will tell you more about it soon.</p> <p>For a more interesting theorem, let’s show that if <code class="docutils literal notranslate"><span class="pre">s</span></code> converges to <code class="docutils literal notranslate"><span class="pre">a</span></code> and <code class="docutils literal notranslate"><span class="pre">t</span></code> converges to <code class="docutils literal notranslate"><span class="pre">b</span></code>, then <code class="docutils literal notranslate"><span class="pre">fun</span> <span class="pre">n</span> <span class="pre">↦</span> <span class="pre">s</span> <span class="pre">n</span> <span class="pre">+</span> <span class="pre">t</span> <span class="pre">n</span></code> converges to <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">+</span> <span class="pre">b</span></code>. It is helpful to have a clear pen-and-paper proof in mind before you start writing a formal one. Given <code class="docutils literal notranslate"><span class="pre">ε</span></code> greater than <code class="docutils literal notranslate"><span class="pre">0</span></code>, the idea is to use the hypotheses to obtain an <code class="docutils literal notranslate"><span class="pre">Ns</span></code> such that beyond that point, <code class="docutils literal notranslate"><span class="pre">s</span></code> is within <code class="docutils literal notranslate"><span class="pre">ε</span> <span class="pre">/</span> <span class="pre">2</span></code> of <code class="docutils literal notranslate"><span class="pre">a</span></code>, and an <code class="docutils literal notranslate"><span class="pre">Nt</span></code> such that beyond that point, <code class="docutils literal notranslate"><span class="pre">t</span></code> is within <code class="docutils literal notranslate"><span class="pre">ε</span> <span class="pre">/</span> <span class="pre">2</span></code> of <code class="docutils literal notranslate"><span class="pre">b</span></code>. Then, whenever <code class="docutils literal notranslate"><span class="pre">n</span></code> is greater than or equal to the maximum of <code class="docutils literal notranslate"><span class="pre">Ns</span></code> and <code class="docutils literal notranslate"><span class="pre">Nt</span></code>, the sequence <code class="docutils literal notranslate"><span class="pre">fun</span> <span class="pre">n</span> <span class="pre">↦</span> <span class="pre">s</span> <span class="pre">n</span> <span class="pre">+</span> <span class="pre">t</span> <span class="pre">n</span></code> should be within <code class="docutils literal notranslate"><span class="pre">ε</span></code> of <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">+</span> <span class="pre">b</span></code>. The following example begins to implement this strategy. See if you can finish it off.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">convergesTo_add</span> <span class="o">{</span><span class="n">s</span> <span class="n">t</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">cs</span> <span class="o">:</span> <span class="n">ConvergesTo</span> <span class="n">s</span> <span class="n">a</span><span class="o">)</span> <span class="o">(</span><span class="n">ct</span> <span class="o">:</span> <span class="n">ConvergesTo</span> <span class="n">t</span> <span class="n">b</span><span class="o">)</span> <span class="o">:</span> <span class="n">ConvergesTo</span> <span class="o">(</span><span class="k">fun</span> <span class="n">n</span> <span class="bp">=></span> <span class="n">s</span> <span class="n">n</span> <span class="bp">+</span> <span class="n">t</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">ε</span> <span class="n">εpos</span> <span class="n">dsimp</span> <span class="k">have</span> <span class="n">ε2pos</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">/</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">linarith</span> <span class="n">cases'</span> <span class="n">cs</span> <span class="o">(</span><span class="n">ε</span> <span class="bp">/</span> <span class="mi">2</span><span class="o">)</span> <span class="n">ε2pos</span> <span class="k">with</span> <span class="n">Ns</span> <span class="n">hs</span> <span class="n">cases'</span> <span class="n">ct</span> <span class="o">(</span><span class="n">ε</span> <span class="bp">/</span> <span class="mi">2</span><span class="o">)</span> <span class="n">ε2pos</span> <span class="k">with</span> <span class="n">Nt</span> <span class="n">ht</span> <span class="n">use</span> <span class="n">max</span> <span class="n">Ns</span> <span class="n">Nt</span> <span class="gr">sorry</span> </pre></div> </div> <p>As hints, you can use <code class="docutils literal notranslate"><span class="pre">le_of_max_le_left</span></code> and <code class="docutils literal notranslate"><span class="pre">le_of_max_le_right</span></code>, and <code class="docutils literal notranslate"><span class="pre">norm_num</span></code> can prove <code class="docutils literal notranslate"><span class="pre">ε</span> <span class="pre">/</span> <span class="pre">2</span> <span class="pre">+</span> <span class="pre">ε</span> <span class="pre">/</span> <span class="pre">2</span> <span class="pre">=</span> <span class="pre">ε</span></code>. Also, it is helpful to use the <code class="docutils literal notranslate"><span class="pre">congr</span></code> tactic to show that <code class="docutils literal notranslate"><span class="pre">abs</span> <span class="pre">(s</span> <span class="pre">n</span> <span class="pre">+</span> <span class="pre">t</span> <span class="pre">n</span> <span class="pre">-</span> <span class="pre">(a</span> <span class="pre">+</span> <span class="pre">b))</span></code> is equal to <code class="docutils literal notranslate"><span class="pre">abs</span> <span class="pre">((s</span> <span class="pre">n</span> <span class="pre">-</span> <span class="pre">a)</span> <span class="pre">+</span> <span class="pre">(t</span> <span class="pre">n</span> <span class="pre">-</span> <span class="pre">b)),</span></code> since then you can use the triangle inequality. Notice that we marked all the variables <code class="docutils literal notranslate"><span class="pre">s</span></code>, <code class="docutils literal notranslate"><span class="pre">t</span></code>, <code class="docutils literal notranslate"><span class="pre">a</span></code>, and <code class="docutils literal notranslate"><span class="pre">b</span></code> implicit because they can be inferred from the hypotheses.</p> <p>Proving the same theorem with multiplication in place of addition is tricky. We will get there by proving some auxiliary statements first. See if you can also finish off the next proof, which shows that if <code class="docutils literal notranslate"><span class="pre">s</span></code> converges to <code class="docutils literal notranslate"><span class="pre">a</span></code>, then <code class="docutils literal notranslate"><span class="pre">fun</span> <span class="pre">n</span> <span class="pre">=></span> <span class="pre">c</span> <span class="pre">*</span> <span class="pre">s</span> <span class="pre">n</span></code> converges to <code class="docutils literal notranslate"><span class="pre">c</span> <span class="pre">*</span> <span class="pre">a</span></code>. It is helpful to split into cases depending on whether <code class="docutils literal notranslate"><span class="pre">c</span></code> is equal to zero or not. We have taken care of the zero case, and we have left you to prove the result with the extra assumption that <code class="docutils literal notranslate"><span class="pre">c</span></code> is nonzero.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">convergesTo_mul_const</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">{</span><span class="n">a</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">c</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">cs</span> <span class="o">:</span> <span class="n">ConvergesTo</span> <span class="n">s</span> <span class="n">a</span><span class="o">)</span> <span class="o">:</span> <span class="n">ConvergesTo</span> <span class="o">(</span><span class="k">fun</span> <span class="n">n</span> <span class="bp">=></span> <span class="n">c</span> <span class="bp">*</span> <span class="n">s</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">c</span> <span class="bp">*</span> <span class="n">a</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">by_cases</span> <span class="n">h</span> <span class="o">:</span> <span class="n">c</span> <span class="bp">=</span> <span class="mi">0</span> <span class="bp">·</span> <span class="n">convert</span> <span class="n">convergesTo_const</span> <span class="mi">0</span> <span class="bp">·</span> <span class="n">rw</span> <span class="o">[</span><span class="n">h</span><span class="o">,</span> <span class="n">MulZeroClass.zero_mul</span><span class="o">]</span> <span class="n">rw</span> <span class="o">[</span><span class="n">h</span><span class="o">,</span> <span class="n">MulZeroClass.zero_mul</span><span class="o">]</span> <span class="k">have</span> <span class="n">acpos</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">abs</span> <span class="n">c</span> <span class="o">:=</span> <span class="n">abs_pos.mpr</span> <span class="n">h</span> <span class="gr">sorry</span> </pre></div> </div> <p>The next theorem is also independently interesting: it shows that a convergent sequence is eventually bounded in absolute value. We have started you off; see if you can finish it.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">exists_abs_le_of_convergesTo</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">{</span><span class="n">a</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">cs</span> <span class="o">:</span> <span class="n">ConvergesTo</span> <span class="n">s</span> <span class="n">a</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">N</span> <span class="n">b</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="n">N</span> <span class="bp">≤</span> <span class="n">n</span> <span class="bp">→</span> <span class="n">abs</span> <span class="o">(</span><span class="n">s</span> <span class="n">n</span><span class="o">)</span> <span class="bp"><</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">cases'</span> <span class="n">cs</span> <span class="mi">1</span> <span class="n">zero_lt_one</span> <span class="k">with</span> <span class="n">N</span> <span class="n">h</span> <span class="n">use</span> <span class="n">N</span><span class="o">,</span> <span class="n">abs</span> <span class="n">a</span> <span class="bp">+</span> <span class="mi">1</span> <span class="gr">sorry</span> </pre></div> </div> <p>In fact, the theorem could be strengthened to assert that there is a bound <code class="docutils literal notranslate"><span class="pre">b</span></code> that holds for all values of <code class="docutils literal notranslate"><span class="pre">n</span></code>. But this version is strong enough for our purposes, and we will see at the end of this section that it holds more generally.</p> <p>The next lemma is auxiliary: we prove that if <code class="docutils literal notranslate"><span class="pre">s</span></code> converges to <code class="docutils literal notranslate"><span class="pre">a</span></code> and <code class="docutils literal notranslate"><span class="pre">t</span></code> converges to <code class="docutils literal notranslate"><span class="pre">0</span></code>, then <code class="docutils literal notranslate"><span class="pre">fun</span> <span class="pre">n</span> <span class="pre">=></span> <span class="pre">s</span> <span class="pre">n</span> <span class="pre">*</span> <span class="pre">t</span> <span class="pre">n</span></code> converges to <code class="docutils literal notranslate"><span class="pre">0</span></code>. To do so, we use the previous theorem to find a <code class="docutils literal notranslate"><span class="pre">B</span></code> that bounds <code class="docutils literal notranslate"><span class="pre">s</span></code> beyond some point <code class="docutils literal notranslate"><span class="pre">N₀</span></code>. See if you can understand the strategy we have outlined and finish the proof.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">aux</span> <span class="o">{</span><span class="n">s</span> <span class="n">t</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">{</span><span class="n">a</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">cs</span> <span class="o">:</span> <span class="n">ConvergesTo</span> <span class="n">s</span> <span class="n">a</span><span class="o">)</span> <span class="o">(</span><span class="n">ct</span> <span class="o">:</span> <span class="n">ConvergesTo</span> <span class="n">t</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="n">ConvergesTo</span> <span class="o">(</span><span class="k">fun</span> <span class="n">n</span> <span class="bp">=></span> <span class="n">s</span> <span class="n">n</span> <span class="bp">*</span> <span class="n">t</span> <span class="n">n</span><span class="o">)</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">ε</span> <span class="n">εpos</span> <span class="n">dsimp</span> <span class="n">rcases</span> <span class="n">exists_abs_le_of_convergesTo</span> <span class="n">cs</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">N₀</span><span class="o">,</span> <span class="n">B</span><span class="o">,</span> <span class="n">h₀</span><span class="o">⟩</span> <span class="k">have</span> <span class="n">Bpos</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">B</span> <span class="o">:=</span> <span class="n">lt_of_le_of_lt</span> <span class="o">(</span><span class="n">abs_nonneg</span> <span class="n">_</span><span class="o">)</span> <span class="o">(</span><span class="n">h₀</span> <span class="n">N₀</span> <span class="o">(</span><span class="n">le_refl</span> <span class="n">_</span><span class="o">))</span> <span class="k">have</span> <span class="n">pos₀</span> <span class="o">:</span> <span class="n">ε</span> <span class="bp">/</span> <span class="n">B</span> <span class="bp">></span> <span class="mi">0</span> <span class="o">:=</span> <span class="n">div_pos</span> <span class="n">εpos</span> <span class="n">Bpos</span> <span class="n">cases'</span> <span class="n">ct</span> <span class="n">_</span> <span class="n">pos₀</span> <span class="k">with</span> <span class="n">N₁</span> <span class="n">h₁</span> <span class="gr">sorry</span> </pre></div> </div> <p>If you have made it this far, congratulations! We are now within striking distance of our theorem. The following proof finishes it off.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">convergesTo_mul</span> <span class="o">{</span><span class="n">s</span> <span class="n">t</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">cs</span> <span class="o">:</span> <span class="n">ConvergesTo</span> <span class="n">s</span> <span class="n">a</span><span class="o">)</span> <span class="o">(</span><span class="n">ct</span> <span class="o">:</span> <span class="n">ConvergesTo</span> <span class="n">t</span> <span class="n">b</span><span class="o">)</span> <span class="o">:</span> <span class="n">ConvergesTo</span> <span class="o">(</span><span class="k">fun</span> <span class="n">n</span> <span class="bp">=></span> <span class="n">s</span> <span class="n">n</span> <span class="bp">*</span> <span class="n">t</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="k">have</span> <span class="n">h₁</span> <span class="o">:</span> <span class="n">ConvergesTo</span> <span class="o">(</span><span class="k">fun</span> <span class="n">n</span> <span class="bp">=></span> <span class="n">s</span> <span class="n">n</span> <span class="bp">*</span> <span class="o">(</span><span class="n">t</span> <span class="n">n</span> <span class="bp">+</span> <span class="bp">-</span><span class="n">b</span><span class="o">))</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">aux</span> <span class="n">cs</span> <span class="n">convert</span> <span class="n">convergesTo_add</span> <span class="n">ct</span> <span class="o">(</span><span class="n">convergesTo_const</span> <span class="o">(</span><span class="bp">-</span><span class="n">b</span><span class="o">))</span> <span class="n">ring</span> <span class="k">have</span> <span class="o">:=</span> <span class="n">convergesTo_add</span> <span class="n">h₁</span> <span class="o">(</span><span class="n">convergesTo_mul_const</span> <span class="n">b</span> <span class="n">cs</span><span class="o">)</span> <span class="n">convert</span> <span class="n">convergesTo_add</span> <span class="n">h₁</span> <span class="o">(</span><span class="n">convergesTo_mul_const</span> <span class="n">b</span> <span class="n">cs</span><span class="o">)</span> <span class="n">using</span> <span class="mi">1</span> <span class="bp">·</span> <span class="n">ext</span><span class="bp">;</span> <span class="n">ring</span> <span class="n">ring</span> </pre></div> </div> <p>For another challenging exercise, try filling out the following sketch of a proof that limits are unique. (If you are feeling bold, you can delete the proof sketch and try proving it from scratch.)</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">convergesTo_unique</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">sa</span> <span class="o">:</span> <span class="n">ConvergesTo</span> <span class="n">s</span> <span class="n">a</span><span class="o">)</span> <span class="o">(</span><span class="n">sb</span> <span class="o">:</span> <span class="n">ConvergesTo</span> <span class="n">s</span> <span class="n">b</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">by_contra</span> <span class="n">abne</span> <span class="k">have</span> <span class="o">:</span> <span class="n">abs</span> <span class="o">(</span><span class="n">a</span> <span class="bp">-</span> <span class="n">b</span><span class="o">)</span> <span class="bp">></span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">let</span> <span class="n">ε</span> <span class="o">:=</span> <span class="n">abs</span> <span class="o">(</span><span class="n">a</span> <span class="bp">-</span> <span class="n">b</span><span class="o">)</span> <span class="bp">/</span> <span class="mi">2</span> <span class="k">have</span> <span class="n">εpos</span> <span class="o">:</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">change</span> <span class="n">abs</span> <span class="o">(</span><span class="n">a</span> <span class="bp">-</span> <span class="n">b</span><span class="o">)</span> <span class="bp">/</span> <span class="mi">2</span> <span class="bp">></span> <span class="mi">0</span> <span class="n">linarith</span> <span class="n">cases'</span> <span class="n">sa</span> <span class="n">ε</span> <span class="n">εpos</span> <span class="k">with</span> <span class="n">Na</span> <span class="n">hNa</span> <span class="n">cases'</span> <span class="n">sb</span> <span class="n">ε</span> <span class="n">εpos</span> <span class="k">with</span> <span class="n">Nb</span> <span class="n">hNb</span> <span class="k">let</span> <span class="n">N</span> <span class="o">:=</span> <span class="n">max</span> <span class="n">Na</span> <span class="n">Nb</span> <span class="k">have</span> <span class="n">absa</span> <span class="o">:</span> <span class="n">abs</span> <span class="o">(</span><span class="n">s</span> <span class="n">N</span> <span class="bp">-</span> <span class="n">a</span><span class="o">)</span> <span class="bp"><</span> <span class="n">ε</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="n">absb</span> <span class="o">:</span> <span class="n">abs</span> <span class="o">(</span><span class="n">s</span> <span class="n">N</span> <span class="bp">-</span> <span class="n">b</span><span class="o">)</span> <span class="bp"><</span> <span class="n">ε</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="o">:</span> <span class="n">abs</span> <span class="o">(</span><span class="n">a</span> <span class="bp">-</span> <span class="n">b</span><span class="o">)</span> <span class="bp"><</span> <span class="n">abs</span> <span class="o">(</span><span class="n">a</span> <span class="bp">-</span> <span class="n">b</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="n">exact</span> <span class="n">lt_irrefl</span> <span class="n">_</span> <span class="n">this</span> </pre></div> </div> <p>We close the section with the observation that our proofs can be generalized. For example, the only properties that we have used of the natural numbers is that their structure carries a partial order with <code class="docutils literal notranslate"><span class="pre">min</span></code> and <code class="docutils literal notranslate"><span class="pre">max</span></code>. You can check that everything still works if you replace <code class="docutils literal notranslate"><span class="pre">ℕ</span></code> everywhere by any linear order <code class="docutils literal notranslate"><span class="pre">α</span></code>:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">LinearOrder</span> <span class="n">α</span><span class="o">]</span> <span class="kd">def</span> <span class="n">ConvergesTo'</span> <span class="o">(</span><span class="n">s</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:=</span> <span class="bp">∀</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">N</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">n</span> <span class="bp">≥</span> <span class="n">N</span><span class="o">,</span> <span class="n">abs</span> <span class="o">(</span><span class="n">s</span> <span class="n">n</span> <span class="bp">-</span> <span class="n">a</span><span class="o">)</span> <span class="bp"><</span> <span class="n">ε</span> </pre></div> </div> <p>In <a class="reference internal" href="C08_Topology.html#filters"><span class="std std-numref">Section 8.1</span></a>, we will see that mathlib has mechanisms for dealing with convergence in vastly more general terms, not only abstracting away particular features of the domain and codomain, but also abstracting over different types of convergence.</p> </section> </section> </div> </div> <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> <a href="C02_Basics.html" class="btn btn-neutral float-left" title="2. Basics" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> <a href="C04_Sets_and_Functions.html" class="btn btn-neutral float-right" title="4. Sets and Functions" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> </div> <hr/> <div role="contentinfo"> <p>© Copyright 2020, Jeremy Avigad, Kevin Buzzard, Robert Y. Lewis, Patrick Massot.</p> </div> Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. </footer> </div> </div> </section> </div> <script> jQuery(function () { SphinxRtdTheme.Navigation.enable(true); }); </script> </body> </html>
-
-
-
@@ -0,0 +1,1194 @@<!DOCTYPE html> <html class="writer-html5" lang="en" > <head> <meta charset="utf-8" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>4. Sets and Functions — Mathematics in Lean 0.1 documentation</title> <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> <link rel="stylesheet" href="_static/css/custom.css" type="text/css" /> <link rel="shortcut icon" href="_static/favicon.ico"/> <!--[if lt IE 9]> <script src="_static/js/html5shiv.min.js"></script> <![endif]--> <script src="_static/jquery.js"></script> <script src="_static/_sphinx_javascript_frameworks_compat.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script src="_static/doctools.js"></script> <script src="_static/sphinx_highlight.js"></script> <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> <script src="_static/js/theme.js"></script> <link rel="index" title="Index" href="genindex.html" /> <link rel="search" title="Search" href="search.html" /> <link rel="next" title="5. Number Theory" href="C05_Number_Theory.html" /> <link rel="prev" title="3. Logic" href="C03_Logic.html" /> </head> <body class="wy-body-for-nav"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search" > <a href="index.html" class="icon icon-home"> Mathematics in Lean </a> <div role="search"> <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> <ul class="current"> <li class="toctree-l1"><a class="reference internal" href="C01_Introduction.html">1. Introduction</a></li> <li class="toctree-l1"><a class="reference internal" href="C02_Basics.html">2. Basics</a></li> <li class="toctree-l1"><a class="reference internal" href="C03_Logic.html">3. Logic</a></li> <li class="toctree-l1 current"><a class="current reference internal" href="#">4. Sets and Functions</a><ul> <li class="toctree-l2"><a class="reference internal" href="#sets">4.1. Sets</a></li> <li class="toctree-l2"><a class="reference internal" href="#functions">4.2. Functions</a></li> <li class="toctree-l2"><a class="reference internal" href="#the-schroder-bernstein-theorem">4.3. The Schröder-Bernstein Theorem</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="C05_Number_Theory.html">5. Number Theory</a></li> <li class="toctree-l1"><a class="reference internal" href="C06_Structures.html">6. Structures</a></li> <li class="toctree-l1"><a class="reference internal" href="C07_Hierarchies.html">7. Hierarchies</a></li> <li class="toctree-l1"><a class="reference internal" href="C08_Topology.html">8. Topology</a></li> <li class="toctree-l1"><a class="reference internal" href="C09_Differential_Calculus.html">9. Differential Calculus</a></li> </ul> <ul> <li class="toctree-l1"><a class="reference internal" href="genindex.html">Index</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="index.html">Mathematics in Lean</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="Page navigation"> <ul class="wy-breadcrumbs"> <li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li> <li class="breadcrumb-item active"><span class="section-number">4. </span>Sets and Functions</li> <li class="wy-breadcrumbs-aside"> <a href="_sources/C04_Sets_and_Functions.rst.txt" rel="nofollow"> View page source</a> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <section id="sets-and-functions"> <span id="id1"></span><h1><span class="section-number">4. </span>Sets and Functions<a class="headerlink" href="#sets-and-functions" title="Permalink to this heading"></a></h1> <p>The vocabulary of sets, relations, and functions provides a uniform language for carrying out constructions in all the branches of mathematics. Since functions and relations can be defined in terms of sets, axiomatic set theory can be used as a foundation for mathematics.</p> <p>Lean’s foundation is based instead on the primitive notion of a <em>type</em>, and it includes ways of defining functions between types. Every expression in Lean has a type: there are natural numbers, real numbers, functions from reals to reals, groups, vector spaces, and so on. Some expressions <em>are</em> types, which is to say, their type is <code class="docutils literal notranslate"><span class="pre">Type</span></code>. Lean and mathlib provide ways of defining new types, and ways of defining objects of those types.</p> <p>Conceptually, you can think of a type as just a set of objects. Requiring every object to have a type has some advantages. For example, it makes it possible to overload notation like <code class="docutils literal notranslate"><span class="pre">+</span></code>, and it sometimes makes input less verbose because Lean can infer a lot of information from an object’s type. The type system also enables Lean to flag errors when you apply a function to the wrong number of arguments, or apply a function to arguments of the wrong type.</p> <p>Lean’s library does define elementary set-theoretic notions. In contrast to set theory, in Lean a set is always a set of objects of some type, such as a set natural numbers or a set of functions from real numbers to real numbers. The distinction between types and set takes some getting used to, but this chapter will take you through the essentials.</p> <section id="sets"> <span id="id2"></span><h2><span class="section-number">4.1. </span>Sets<a class="headerlink" href="#sets" title="Permalink to this heading"></a></h2> <p id="index-0">If <code class="docutils literal notranslate"><span class="pre">α</span></code> is any type, the type <code class="docutils literal notranslate"><span class="pre">Set</span> <span class="pre">α</span></code> consists of sets of elements of <code class="docutils literal notranslate"><span class="pre">α</span></code>. This type supports the usual set-theoretic operations and relations. For example, <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">⊆</span> <span class="pre">t</span></code> says that <code class="docutils literal notranslate"><span class="pre">s</span></code> is a subset of <code class="docutils literal notranslate"><span class="pre">t</span></code>, <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">∩</span> <span class="pre">t</span></code> denotes the intersection of <code class="docutils literal notranslate"><span class="pre">s</span></code> and <code class="docutils literal notranslate"><span class="pre">t</span></code>, and <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">∪</span> <span class="pre">t</span></code> denotes their union. The subset relation can be typed with <code class="docutils literal notranslate"><span class="pre">\ss</span></code> or <code class="docutils literal notranslate"><span class="pre">\sub</span></code>, intersection can be typed with <code class="docutils literal notranslate"><span class="pre">\i</span></code> or <code class="docutils literal notranslate"><span class="pre">\cap</span></code>, and union can be typed with <code class="docutils literal notranslate"><span class="pre">\un</span></code> or <code class="docutils literal notranslate"><span class="pre">\cup</span></code>. The library also defines the set <code class="docutils literal notranslate"><span class="pre">univ</span></code>, which consists of all the elements of type <code class="docutils literal notranslate"><span class="pre">α</span></code>, and the empty set, <code class="docutils literal notranslate"><span class="pre">∅</span></code>, which can be typed as <code class="docutils literal notranslate"><span class="pre">\empty</span></code>. Given <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">:</span> <span class="pre">α</span></code> and <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">:</span> <span class="pre">Set</span> <span class="pre">α</span></code>, the expression <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span></code> says that <code class="docutils literal notranslate"><span class="pre">x</span></code> is a member of <code class="docutils literal notranslate"><span class="pre">s</span></code>. Theorems that mention set membership often include <code class="docutils literal notranslate"><span class="pre">mem</span></code> in their name. The expression <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">∉</span> <span class="pre">s</span></code> abbreviates <code class="docutils literal notranslate"><span class="pre">¬</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span></code>. You can type <code class="docutils literal notranslate"><span class="pre">∈</span></code> as <code class="docutils literal notranslate"><span class="pre">\in</span></code> or <code class="docutils literal notranslate"><span class="pre">\mem</span></code> and <code class="docutils literal notranslate"><span class="pre">∉</span></code> as <code class="docutils literal notranslate"><span class="pre">\notin</span></code>.</p> <p id="index-1">One way to prove things about sets is to use <code class="docutils literal notranslate"><span class="pre">rw</span></code> or the simplifier to expand the definitions. In the second example below, we use <code class="docutils literal notranslate"><span class="pre">simp</span> <span class="pre">only</span></code> to tell the simplifier to use only the list of identities we give it, and not its full database of identities. Unlike <code class="docutils literal notranslate"><span class="pre">rw</span></code>, <code class="docutils literal notranslate"><span class="pre">simp</span></code> can perform simplifications inside a universal or existential quantifier. If you step through the proof, you can see the effects of these commands.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">s</span> <span class="n">t</span> <span class="n">u</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">α</span><span class="o">)</span> <span class="kn">open</span> <span class="n">Set</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="n">t</span><span class="o">)</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">u</span> <span class="bp">⊆</span> <span class="n">t</span> <span class="bp">∩</span> <span class="n">u</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">subset_def</span><span class="o">,</span> <span class="n">inter_def</span><span class="o">,</span> <span class="n">inter_def</span><span class="o">]</span> <span class="n">rw</span> <span class="o">[</span><span class="n">subset_def</span><span class="o">]</span> <span class="n">at</span> <span class="n">h</span> <span class="n">dsimp</span> <span class="n">rintro</span> <span class="n">x</span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="n">xu</span><span class="o">⟩</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">h</span> <span class="n">_</span> <span class="n">xs</span><span class="o">,</span> <span class="n">xu</span><span class="o">⟩</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="n">t</span><span class="o">)</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">u</span> <span class="bp">⊆</span> <span class="n">t</span> <span class="bp">∩</span> <span class="n">u</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="n">only</span> <span class="o">[</span><span class="n">subset_def</span><span class="o">,</span> <span class="n">mem_inter_iff</span><span class="o">]</span> <span class="n">at</span> <span class="bp">*</span> <span class="n">rintro</span> <span class="n">x</span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="n">xu</span><span class="o">⟩</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">h</span> <span class="n">_</span> <span class="n">xs</span><span class="o">,</span> <span class="n">xu</span><span class="o">⟩</span> </pre></div> </div> <p>In this example, we open the <code class="docutils literal notranslate"><span class="pre">set</span></code> namespace to have access to the shorter names for the theorems. But, in fact, we can delete the calls to <code class="docutils literal notranslate"><span class="pre">rw</span></code> and <code class="docutils literal notranslate"><span class="pre">simp</span></code> entirely:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="n">t</span><span class="o">)</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">u</span> <span class="bp">⊆</span> <span class="n">t</span> <span class="bp">∩</span> <span class="n">u</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">xsu</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">h</span> <span class="n">xsu.1</span><span class="o">,</span> <span class="n">xsu.2</span><span class="o">⟩</span> </pre></div> </div> <p>What is going on here is known as <em>definitional reduction</em>: to make sense of the <code class="docutils literal notranslate"><span class="pre">intro</span></code> command and the anonymous constructors Lean is forced to expand the definitions. The following examples also illustrate the phenomenon:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">foo</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="n">t</span><span class="o">)</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">u</span> <span class="bp">⊆</span> <span class="n">t</span> <span class="bp">∩</span> <span class="n">u</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">x</span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="n">xu</span><span class="o">⟩</span> <span class="bp">=></span> <span class="o">⟨</span><span class="n">h</span> <span class="n">xs</span><span class="o">,</span> <span class="n">xu</span><span class="o">⟩</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="n">t</span><span class="o">)</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">u</span> <span class="bp">⊆</span> <span class="n">t</span> <span class="bp">∩</span> <span class="n">u</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">x</span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="n">xu</span><span class="o">⟩</span> <span class="bp">=></span> <span class="o">⟨</span><span class="n">h</span> <span class="n">xs</span><span class="o">,</span> <span class="n">xu</span><span class="o">⟩</span> </pre></div> </div> <p>Due to a quirk of how Lean processes its input, the first example fails if we replace <code class="docutils literal notranslate"><span class="pre">theorem</span> <span class="pre">foo</span></code> with <code class="docutils literal notranslate"><span class="pre">example</span></code>. This illustrates the pitfalls of relying on definitional reduction too heavily. It is often convenient, but sometimes we have to fall back on unfolding definitions manually.</p> <p>To deal with unions, we can use <code class="docutils literal notranslate"><span class="pre">Set.union_def</span></code> and <code class="docutils literal notranslate"><span class="pre">Set.mem_union</span></code>. Since <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span> <span class="pre">∪</span> <span class="pre">t</span></code> unfolds to <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span> <span class="pre">∨</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">t</span></code>, we can also use the <code class="docutils literal notranslate"><span class="pre">cases</span></code> tactic to force a definitional reduction.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∩</span> <span class="o">(</span><span class="n">t</span> <span class="bp">∪</span> <span class="n">u</span><span class="o">)</span> <span class="bp">⊆</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">t</span> <span class="bp">∪</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">u</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">hx</span> <span class="k">have</span> <span class="n">xs</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s</span> <span class="o">:=</span> <span class="n">hx.1</span> <span class="k">have</span> <span class="n">xtu</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">t</span> <span class="bp">∪</span> <span class="n">u</span> <span class="o">:=</span> <span class="n">hx.2</span> <span class="n">cases'</span> <span class="n">xtu</span> <span class="k">with</span> <span class="n">xt</span> <span class="n">xu</span> <span class="bp">·</span> <span class="n">left</span> <span class="k">show</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">t</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="n">xt</span><span class="o">⟩</span> <span class="n">right</span> <span class="k">show</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">u</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="n">xu</span><span class="o">⟩</span> </pre></div> </div> <p>Since intersection binds tighter than union, the use of parentheses in the expression <code class="docutils literal notranslate"><span class="pre">(s</span> <span class="pre">∩</span> <span class="pre">t)</span> <span class="pre">∪</span> <span class="pre">(s</span> <span class="pre">∩</span> <span class="pre">u)</span></code> is unnecessary, but they make the meaning of the expression clearer. The following is a shorter proof of the same fact:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∩</span> <span class="o">(</span><span class="n">t</span> <span class="bp">∪</span> <span class="n">u</span><span class="o">)</span> <span class="bp">⊆</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">t</span> <span class="bp">∪</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">u</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rintro</span> <span class="n">x</span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="n">xt</span> <span class="bp">|</span> <span class="n">xu</span><span class="o">⟩</span> <span class="bp">·</span> <span class="n">left</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="n">xt</span><span class="o">⟩</span> <span class="n">right</span><span class="bp">;</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="n">xu</span><span class="o">⟩</span> </pre></div> </div> <p>As an exercise, try proving the other inclusion:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">t</span> <span class="bp">∪</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">u</span> <span class="bp">⊆</span> <span class="n">s</span> <span class="bp">∩</span> <span class="o">(</span><span class="n">t</span> <span class="bp">∪</span> <span class="n">u</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>It might help to know that when using <code class="docutils literal notranslate"><span class="pre">rintro</span></code>, sometimes we need to use parentheses around a disjunctive pattern <code class="docutils literal notranslate"><span class="pre">h1</span> <span class="pre">|</span> <span class="pre">h2</span></code> to get Lean to parse it correctly.</p> <p>The library also defines set difference, <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">\</span> <span class="pre">t</span></code>, where the backslash is a special unicode character entered as <code class="docutils literal notranslate"><span class="pre">\\</span></code>. The expression <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span> <span class="pre">\</span> <span class="pre">t</span></code> expands to <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span> <span class="pre">∧</span> <span class="pre">x</span> <span class="pre">∉</span> <span class="pre">t</span></code>. (The <code class="docutils literal notranslate"><span class="pre">∉</span></code> can be entered as <code class="docutils literal notranslate"><span class="pre">\notin</span></code>.) It can be rewritten manually using <code class="docutils literal notranslate"><span class="pre">Set.diff_eq</span></code> and <code class="docutils literal notranslate"><span class="pre">dsimp</span></code> or <code class="docutils literal notranslate"><span class="pre">Set.mem_diff</span></code>, but the following two proofs of the same inclusion show how to avoid using them.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">s</span> <span class="bp">\</span> <span class="n">t</span><span class="o">)</span> <span class="bp">\</span> <span class="n">u</span> <span class="bp">⊆</span> <span class="n">s</span> <span class="bp">\</span> <span class="o">(</span><span class="n">t</span> <span class="bp">∪</span> <span class="n">u</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">xstu</span> <span class="k">have</span> <span class="n">xs</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s</span> <span class="o">:=</span> <span class="n">xstu.1.1</span> <span class="k">have</span> <span class="n">xnt</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∉</span> <span class="n">t</span> <span class="o">:=</span> <span class="n">xstu.1.2</span> <span class="k">have</span> <span class="n">xnu</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∉</span> <span class="n">u</span> <span class="o">:=</span> <span class="n">xstu.2</span> <span class="n">constructor</span> <span class="bp">·</span> <span class="n">exact</span> <span class="n">xs</span> <span class="n">intro</span> <span class="n">xtu</span> <span class="c1">-- x ∈ t ∨ x ∈ u</span> <span class="n">cases'</span> <span class="n">xtu</span> <span class="k">with</span> <span class="n">xt</span> <span class="n">xu</span> <span class="bp">·</span> <span class="k">show</span> <span class="n">False</span> <span class="n">exact</span> <span class="n">xnt</span> <span class="n">xt</span> <span class="k">show</span> <span class="n">False</span><span class="bp">;</span> <span class="n">exact</span> <span class="n">xnu</span> <span class="n">xu</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">s</span> <span class="bp">\</span> <span class="n">t</span><span class="o">)</span> <span class="bp">\</span> <span class="n">u</span> <span class="bp">⊆</span> <span class="n">s</span> <span class="bp">\</span> <span class="o">(</span><span class="n">t</span> <span class="bp">∪</span> <span class="n">u</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rintro</span> <span class="n">x</span> <span class="o">⟨⟨</span><span class="n">xs</span><span class="o">,</span> <span class="n">xnt</span><span class="o">⟩,</span> <span class="n">xnu</span><span class="o">⟩</span> <span class="n">use</span> <span class="n">xs</span> <span class="n">rintro</span> <span class="o">(</span><span class="n">xt</span> <span class="bp">|</span> <span class="n">xu</span><span class="o">)</span> <span class="bp"><;></span> <span class="n">contradiction</span> </pre></div> </div> <p>As an exercise, prove the reverse inclusion:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">\</span> <span class="o">(</span><span class="n">t</span> <span class="bp">∪</span> <span class="n">u</span><span class="o">)</span> <span class="bp">⊆</span> <span class="o">(</span><span class="n">s</span> <span class="bp">\</span> <span class="n">t</span><span class="o">)</span> <span class="bp">\</span> <span class="n">u</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>To prove that two sets are equal, it suffices to show that every element of one is an element of the other. This principle is known as “extensionality,” and, unsurprisingly, the <code class="docutils literal notranslate"><span class="pre">ext</span></code> tactic is equipped to handle it.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">t</span> <span class="bp">=</span> <span class="n">t</span> <span class="bp">∩</span> <span class="n">s</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ext</span> <span class="n">x</span> <span class="n">simp</span> <span class="n">only</span> <span class="o">[</span><span class="n">mem_inter_iff</span><span class="o">]</span> <span class="n">constructor</span> <span class="bp">·</span> <span class="n">rintro</span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="n">xt</span><span class="o">⟩</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">xt</span><span class="o">,</span> <span class="n">xs</span><span class="o">⟩</span> <span class="n">rintro</span> <span class="o">⟨</span><span class="n">xt</span><span class="o">,</span> <span class="n">xs</span><span class="o">⟩</span><span class="bp">;</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="n">xt</span><span class="o">⟩</span> </pre></div> </div> <p>Once again, deleting the line <code class="docutils literal notranslate"><span class="pre">simp</span> <span class="pre">only</span> <span class="pre">[mem_inter_iff]</span></code> does not harm the proof. In fact, if you like inscrutable proof terms, the following one-line proof is for you:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">t</span> <span class="bp">=</span> <span class="n">t</span> <span class="bp">∩</span> <span class="n">s</span> <span class="o">:=</span> <span class="n">Set.ext</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="o">⟨</span><span class="k">fun</span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="n">xt</span><span class="o">⟩</span> <span class="bp">=></span> <span class="o">⟨</span><span class="n">xt</span><span class="o">,</span> <span class="n">xs</span><span class="o">⟩,</span> <span class="k">fun</span> <span class="o">⟨</span><span class="n">xt</span><span class="o">,</span> <span class="n">xs</span><span class="o">⟩</span> <span class="bp">=></span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="n">xt</span><span class="o">⟩⟩</span> </pre></div> </div> <p>The dollar sign is a useful syntax: writing <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">$</span> <span class="pre">...</span></code> is essentially the same as writing <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">(...)</span></code>, but it saves us the trouble of having to close a set of parentheses at the end of a long expression. Here is an even shorter proof, using the simplifier:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">t</span> <span class="bp">=</span> <span class="n">t</span> <span class="bp">∩</span> <span class="n">s</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ext</span> <span class="n">x</span><span class="bp">;</span> <span class="n">simp</span> <span class="o">[</span><span class="n">and_comm</span><span class="o">]</span> </pre></div> </div> <p>An alternative to using <code class="docutils literal notranslate"><span class="pre">ext</span></code> is to use the theorem <code class="docutils literal notranslate"><span class="pre">Subset.antisymm</span></code> which allows us to prove an equation <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">=</span> <span class="pre">t</span></code> between sets by proving <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">⊆</span> <span class="pre">t</span></code> and <code class="docutils literal notranslate"><span class="pre">t</span> <span class="pre">⊆</span> <span class="pre">s</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">t</span> <span class="bp">=</span> <span class="n">t</span> <span class="bp">∩</span> <span class="n">s</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">Subset.antisymm</span> <span class="bp">·</span> <span class="n">rintro</span> <span class="n">x</span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="n">xt</span><span class="o">⟩</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">xt</span><span class="o">,</span> <span class="n">xs</span><span class="o">⟩</span> <span class="n">rintro</span> <span class="n">x</span> <span class="o">⟨</span><span class="n">xt</span><span class="o">,</span> <span class="n">xs</span><span class="o">⟩</span><span class="bp">;</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="n">xt</span><span class="o">⟩</span> </pre></div> </div> <p>Try finishing this proof term:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">t</span> <span class="bp">=</span> <span class="n">t</span> <span class="bp">∩</span> <span class="n">s</span> <span class="o">:=</span> <span class="n">Subset.antisymm</span> <span class="gr">sorry</span> <span class="gr">sorry</span> </pre></div> </div> <p>Remember that you can replace <cite>sorry</cite> by an underscore, and when you hover over it, Lean will show you what it expects at that point.</p> <p>Here are some set-theoretic identities you might enjoy proving:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∩</span> <span class="o">(</span><span class="n">s</span> <span class="bp">∪</span> <span class="n">t</span><span class="o">)</span> <span class="bp">=</span> <span class="n">s</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∪</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">t</span> <span class="bp">=</span> <span class="n">s</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">\</span> <span class="n">t</span> <span class="bp">∪</span> <span class="n">t</span> <span class="bp">=</span> <span class="n">s</span> <span class="bp">∪</span> <span class="n">t</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">\</span> <span class="n">t</span> <span class="bp">∪</span> <span class="n">t</span> <span class="bp">\</span> <span class="n">s</span> <span class="bp">=</span> <span class="o">(</span><span class="n">s</span> <span class="bp">∪</span> <span class="n">t</span><span class="o">)</span> <span class="bp">\</span> <span class="o">(</span><span class="n">s</span> <span class="bp">∩</span> <span class="n">t</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>When it comes to representing sets, here is what is going on underneath the hood. In type theory, a <em>property</em> or <em>predicate</em> on a type <code class="docutils literal notranslate"><span class="pre">α</span></code> is just a function <code class="docutils literal notranslate"><span class="pre">P</span> <span class="pre">:</span> <span class="pre">α</span> <span class="pre">→</span> <span class="pre">Prop</span></code>. This makes sense: given <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">:</span> <span class="pre">α</span></code>, <code class="docutils literal notranslate"><span class="pre">P</span> <span class="pre">a</span></code> is just the proposition that <code class="docutils literal notranslate"><span class="pre">P</span></code> holds of <code class="docutils literal notranslate"><span class="pre">a</span></code>. In the library, <code class="docutils literal notranslate"><span class="pre">Set</span> <span class="pre">α</span></code> is defined to be <code class="docutils literal notranslate"><span class="pre">α</span> <span class="pre">→</span> <span class="pre">Prop</span></code> and <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span></code> is defined to be <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">x</span></code>. In other words, sets are really properties, treated as objects.</p> <p>The library also defines set-builder notation. The expression <code class="docutils literal notranslate"><span class="pre">{</span> <span class="pre">y</span> <span class="pre">|</span> <span class="pre">P</span> <span class="pre">y</span> <span class="pre">}</span></code> unfolds to <code class="docutils literal notranslate"><span class="pre">(fun</span> <span class="pre">y</span> <span class="pre">↦</span> <span class="pre">P</span> <span class="pre">y)</span></code>, so <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">∈</span> <span class="pre">{</span> <span class="pre">y</span> <span class="pre">|</span> <span class="pre">P</span> <span class="pre">y</span> <span class="pre">}</span></code> reduces to <code class="docutils literal notranslate"><span class="pre">P</span> <span class="pre">x</span></code>. So we can turn the property of being even into the set of even numbers:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">evens</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">ℕ</span> <span class="o">:=</span> <span class="o">{</span> <span class="n">n</span> <span class="bp">|</span> <span class="n">Even</span> <span class="n">n</span> <span class="o">}</span> <span class="kd">def</span> <span class="n">odds</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">ℕ</span> <span class="o">:=</span> <span class="o">{</span> <span class="n">n</span> <span class="bp">|</span> <span class="bp">¬</span><span class="n">Even</span> <span class="n">n</span> <span class="o">}</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">evens</span> <span class="bp">∪</span> <span class="n">odds</span> <span class="bp">=</span> <span class="n">univ</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">evens</span><span class="o">,</span> <span class="n">odds</span><span class="o">]</span> <span class="n">ext</span> <span class="n">n</span> <span class="n">simp</span> <span class="n">apply</span> <span class="n">Classical.em</span> </pre></div> </div> <p>You should step through this proof and make sure you understand what is going on. Try deleting the line <code class="docutils literal notranslate"><span class="pre">rw</span> <span class="pre">[evens,</span> <span class="pre">odds]</span></code> and confirm that the proof still works.</p> <p>In fact, set-builder notation is used to define</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">∩</span> <span class="pre">t</span></code> as <code class="docutils literal notranslate"><span class="pre">{x</span> <span class="pre">|</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span> <span class="pre">∧</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">t}</span></code>,</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">∪</span> <span class="pre">t</span></code> as <code class="docutils literal notranslate"><span class="pre">{x</span> <span class="pre">|</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span> <span class="pre">∨</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">t}</span></code>,</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">∅</span></code> as <code class="docutils literal notranslate"><span class="pre">{x</span> <span class="pre">|</span> <span class="pre">False}</span></code>, and</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">univ</span></code> as <code class="docutils literal notranslate"><span class="pre">{x</span> <span class="pre">|</span> <span class="pre">True}</span></code>.</p></li> </ul> <p>We often need to indicate the type of <code class="docutils literal notranslate"><span class="pre">∅</span></code> and <code class="docutils literal notranslate"><span class="pre">univ</span></code> explicitly, because Lean has trouble guessing which ones we mean. The following examples show how Lean unfolds the last two definitions when needed. In the second one, <code class="docutils literal notranslate"><span class="pre">trivial</span></code> is the canonical proof of <code class="docutils literal notranslate"><span class="pre">True</span></code> in the library.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∈</span> <span class="o">(</span><span class="bp">∅</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">ℕ</span><span class="o">))</span> <span class="o">:</span> <span class="n">False</span> <span class="o">:=</span> <span class="n">h</span> <span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∈</span> <span class="o">(</span><span class="n">univ</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:=</span> <span class="n">trivial</span> </pre></div> </div> <p>As an exercise, prove the following inclusion. Use <code class="docutils literal notranslate"><span class="pre">intro</span> <span class="pre">n</span></code> to unfold the definition of subset, and use the simplifier to reduce the set-theoretic constructions to logic. We also recommend using the theorems <code class="docutils literal notranslate"><span class="pre">Nat.Prime.eq_two_or_odd</span></code> and <code class="docutils literal notranslate"><span class="pre">Nat.even_iff</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="o">{</span> <span class="n">n</span> <span class="bp">|</span> <span class="n">Nat.Prime</span> <span class="n">n</span> <span class="o">}</span> <span class="bp">∩</span> <span class="o">{</span> <span class="n">n</span> <span class="bp">|</span> <span class="n">n</span> <span class="bp">></span> <span class="mi">2</span> <span class="o">}</span> <span class="bp">⊆</span> <span class="o">{</span> <span class="n">n</span> <span class="bp">|</span> <span class="bp">¬</span><span class="n">Even</span> <span class="n">n</span> <span class="o">}</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Be careful: it is somewhat confusing that the library has multiple versions of the predicate <code class="docutils literal notranslate"><span class="pre">Prime</span></code>. The most general one makes sense in any commutative monoid with a zero element. The predicate <code class="docutils literal notranslate"><span class="pre">Nat.Prime</span></code> is specific to the natural numbers. Fortunately, there is a theorem that says that in the specific case, the two notions agree, so you can always rewrite one to the other.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#print</span> <span class="n">Prime</span> <span class="k">#print</span> <span class="n">Nat.Prime</span> <span class="kd">example</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="n">Prime</span> <span class="n">n</span> <span class="bp">↔</span> <span class="n">Nat.Prime</span> <span class="n">n</span> <span class="o">:=</span> <span class="n">Nat.prime_iff.symm</span> <span class="kd">example</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">Prime</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="n">Nat.Prime</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">Nat.prime_iff</span><span class="o">]</span> <span class="n">exact</span> <span class="n">h</span> </pre></div> </div> <p id="index-2">The <cite>rwa</cite> tactic follows a rewrite with the assumption tactic.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">Prime</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="n">Nat.Prime</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rwa</span> <span class="o">[</span><span class="n">Nat.prime_iff</span><span class="o">]</span> </pre></div> </div> <p id="index-3">Lean introduces the notation <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s,</span> <span class="pre">...</span></code>, “for every <code class="docutils literal notranslate"><span class="pre">x</span></code> in <code class="docutils literal notranslate"><span class="pre">s</span></code> .,” as an abbreviation for <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">x,</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span> <span class="pre">→</span> <span class="pre">...</span></code>. It also introduces the notation <code class="docutils literal notranslate"><span class="pre">∃</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s,</span> <span class="pre">...,</span></code> “there exists an <code class="docutils literal notranslate"><span class="pre">x</span></code> in <code class="docutils literal notranslate"><span class="pre">s</span></code> such that ..” These are sometimes known as <em>bounded quantifiers</em>, because the construction serves to restrict their significance to the set <code class="docutils literal notranslate"><span class="pre">s</span></code>. As a result, theorems in the library that make use of them often contain <code class="docutils literal notranslate"><span class="pre">ball</span></code> or <code class="docutils literal notranslate"><span class="pre">bex</span></code> in the name. The theorem <code class="docutils literal notranslate"><span class="pre">bex_def</span></code> asserts that <code class="docutils literal notranslate"><span class="pre">∃</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s,</span> <span class="pre">...</span></code> is equivalent to <code class="docutils literal notranslate"><span class="pre">∃</span> <span class="pre">x,</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span> <span class="pre">∧</span> <span class="pre">...,</span></code> but when they are used with <code class="docutils literal notranslate"><span class="pre">rintro</span></code>, <code class="docutils literal notranslate"><span class="pre">use</span></code>, and anonymous constructors, these two expressions behave roughly the same. As a result, we usually don’t need to use <code class="docutils literal notranslate"><span class="pre">bex_def</span></code> to transform them explicitly. Here is are some examples of how they are used:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">(</span><span class="n">s</span> <span class="n">t</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">ℕ</span><span class="o">)</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h₀</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="bp">¬</span><span class="n">Even</span> <span class="n">x</span><span class="o">)</span> <span class="o">(</span><span class="n">h₁</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="n">Prime</span> <span class="n">x</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="bp">¬</span><span class="n">Even</span> <span class="n">x</span> <span class="bp">∧</span> <span class="n">Prime</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">xs</span> <span class="n">constructor</span> <span class="bp">·</span> <span class="n">apply</span> <span class="n">h₀</span> <span class="n">x</span> <span class="n">xs</span> <span class="n">apply</span> <span class="n">h₁</span> <span class="n">x</span> <span class="n">xs</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="bp">¬</span><span class="n">Even</span> <span class="n">x</span> <span class="bp">∧</span> <span class="n">Prime</span> <span class="n">x</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="n">Prime</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rcases</span> <span class="n">h</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">x</span><span class="o">,</span> <span class="n">xs</span><span class="o">,</span> <span class="n">_</span><span class="o">,</span> <span class="n">prime_x</span><span class="o">⟩</span> <span class="n">use</span> <span class="n">x</span><span class="o">,</span> <span class="n">xs</span> <span class="n">exact</span> <span class="n">prime_x</span> </pre></div> </div> <p>See if you can prove these slight variations:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">section</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">ssubt</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="n">t</span><span class="o">)</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h₀</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">t</span><span class="o">,</span> <span class="bp">¬</span><span class="n">Even</span> <span class="n">x</span><span class="o">)</span> <span class="o">(</span><span class="n">h₁</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">t</span><span class="o">,</span> <span class="n">Prime</span> <span class="n">x</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="bp">¬</span><span class="n">Even</span> <span class="n">x</span> <span class="bp">∧</span> <span class="n">Prime</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="bp">¬</span><span class="n">Even</span> <span class="n">x</span> <span class="bp">∧</span> <span class="n">Prime</span> <span class="n">x</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">t</span><span class="o">,</span> <span class="n">Prime</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">end</span> </pre></div> </div> <p>Indexed unions and intersections are another important set-theoretic construction. We can model a sequence <span class="math notranslate nohighlight">\(A_0, A_1, A_2, \ldots\)</span> of sets of elements of <code class="docutils literal notranslate"><span class="pre">α</span></code> as a function <code class="docutils literal notranslate"><span class="pre">A</span> <span class="pre">:</span> <span class="pre">ℕ</span> <span class="pre">→</span> <span class="pre">Set</span> <span class="pre">α</span></code>, in which case <code class="docutils literal notranslate"><span class="pre">⋃</span> <span class="pre">i,</span> <span class="pre">A</span> <span class="pre">i</span></code> denotes their union, and <code class="docutils literal notranslate"><span class="pre">⋂</span> <span class="pre">i,</span> <span class="pre">A</span> <span class="pre">i</span></code> denotes their intersection. There is nothing special about the natural numbers here, so <code class="docutils literal notranslate"><span class="pre">ℕ</span></code> can be replaced by any type <code class="docutils literal notranslate"><span class="pre">I</span></code> used to index the sets. The following illustrates their use.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="n">I</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">A</span> <span class="n">B</span> <span class="o">:</span> <span class="n">I</span> <span class="bp">→</span> <span class="n">Set</span> <span class="n">α</span><span class="o">)</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">α</span><span class="o">)</span> <span class="kn">open</span> <span class="n">Set</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">s</span> <span class="bp">∩</span> <span class="bp">⋃</span> <span class="n">i</span><span class="o">,</span> <span class="n">A</span> <span class="n">i</span><span class="o">)</span> <span class="bp">=</span> <span class="bp">⋃</span> <span class="n">i</span><span class="o">,</span> <span class="n">A</span> <span class="n">i</span> <span class="bp">∩</span> <span class="n">s</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ext</span> <span class="n">x</span> <span class="n">simp</span> <span class="n">only</span> <span class="o">[</span><span class="n">mem_inter_iff</span><span class="o">,</span> <span class="n">mem_iUnion</span><span class="o">]</span> <span class="n">constructor</span> <span class="bp">·</span> <span class="n">rintro</span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="o">⟨</span><span class="n">i</span><span class="o">,</span> <span class="n">xAi</span><span class="o">⟩⟩</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">i</span><span class="o">,</span> <span class="n">xAi</span><span class="o">,</span> <span class="n">xs</span><span class="o">⟩</span> <span class="n">rintro</span> <span class="o">⟨</span><span class="n">i</span><span class="o">,</span> <span class="n">xAi</span><span class="o">,</span> <span class="n">xs</span><span class="o">⟩</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">xs</span><span class="o">,</span> <span class="o">⟨</span><span class="n">i</span><span class="o">,</span> <span class="n">xAi</span><span class="o">⟩⟩</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="bp">⋂</span> <span class="n">i</span><span class="o">,</span> <span class="n">A</span> <span class="n">i</span> <span class="bp">∩</span> <span class="n">B</span> <span class="n">i</span><span class="o">)</span> <span class="bp">=</span> <span class="o">(</span><span class="bp">⋂</span> <span class="n">i</span><span class="o">,</span> <span class="n">A</span> <span class="n">i</span><span class="o">)</span> <span class="bp">∩</span> <span class="bp">⋂</span> <span class="n">i</span><span class="o">,</span> <span class="n">B</span> <span class="n">i</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ext</span> <span class="n">x</span> <span class="n">simp</span> <span class="n">only</span> <span class="o">[</span><span class="n">mem_inter_iff</span><span class="o">,</span> <span class="n">mem_iInter</span><span class="o">]</span> <span class="n">constructor</span> <span class="bp">·</span> <span class="n">intro</span> <span class="n">h</span> <span class="n">constructor</span> <span class="bp">·</span> <span class="n">intro</span> <span class="n">i</span> <span class="n">exact</span> <span class="o">(</span><span class="n">h</span> <span class="n">i</span><span class="o">)</span><span class="bp">.</span><span class="mi">1</span> <span class="n">intro</span> <span class="n">i</span> <span class="n">exact</span> <span class="o">(</span><span class="n">h</span> <span class="n">i</span><span class="o">)</span><span class="bp">.</span><span class="mi">2</span> <span class="n">rintro</span> <span class="o">⟨</span><span class="n">h1</span><span class="o">,</span> <span class="n">h2</span><span class="o">⟩</span> <span class="n">i</span> <span class="n">constructor</span> <span class="bp">·</span> <span class="n">exact</span> <span class="n">h1</span> <span class="n">i</span> <span class="n">exact</span> <span class="n">h2</span> <span class="n">i</span> </pre></div> </div> <p>Parentheses are often needed with an indexed union or intersection because, as with the quantifiers, the scope of the bound variable extends as far as it can.</p> <p>Try proving the following identity. One direction requires classical logic! We recommend using <code class="docutils literal notranslate"><span class="pre">by_cases</span> <span class="pre">xs</span> <span class="pre">:</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span></code> at an appropriate point in the proof.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">s</span> <span class="bp">∪</span> <span class="bp">⋂</span> <span class="n">i</span><span class="o">,</span> <span class="n">A</span> <span class="n">i</span><span class="o">)</span> <span class="bp">=</span> <span class="bp">⋂</span> <span class="n">i</span><span class="o">,</span> <span class="n">A</span> <span class="n">i</span> <span class="bp">∪</span> <span class="n">s</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Mathlib also has bounded unions and intersections, which are analogous to the bounded quantifiers. You can unpack their meaning with <code class="docutils literal notranslate"><span class="pre">mem_Union₂</span></code> and <code class="docutils literal notranslate"><span class="pre">mem_Inter₂</span></code>. As the following examples show, Lean’s simplifier carries out these replacements as well.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">primes</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">ℕ</span> <span class="o">:=</span> <span class="o">{</span> <span class="n">x</span> <span class="bp">|</span> <span class="n">Nat.Prime</span> <span class="n">x</span> <span class="o">}</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="bp">⋃</span> <span class="n">p</span> <span class="bp">∈</span> <span class="n">primes</span><span class="o">,</span> <span class="o">{</span> <span class="n">x</span> <span class="bp">|</span> <span class="n">p</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">∣</span> <span class="n">x</span> <span class="o">})</span> <span class="bp">=</span> <span class="o">{</span> <span class="n">x</span> <span class="bp">|</span> <span class="bp">∃</span> <span class="n">p</span> <span class="bp">∈</span> <span class="n">primes</span><span class="o">,</span> <span class="n">p</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">∣</span> <span class="n">x</span> <span class="o">}</span> <span class="o">:=</span><span class="kd">by</span> <span class="n">ext</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mem_iUnion₂</span><span class="o">]</span> <span class="n">simp</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="bp">⋃</span> <span class="n">p</span> <span class="bp">∈</span> <span class="n">primes</span><span class="o">,</span> <span class="o">{</span> <span class="n">x</span> <span class="bp">|</span> <span class="n">p</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">∣</span> <span class="n">x</span> <span class="o">})</span> <span class="bp">=</span> <span class="o">{</span> <span class="n">x</span> <span class="bp">|</span> <span class="bp">∃</span> <span class="n">p</span> <span class="bp">∈</span> <span class="n">primes</span><span class="o">,</span> <span class="n">p</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">∣</span> <span class="n">x</span> <span class="o">}</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ext</span> <span class="n">simp</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="bp">⋂</span> <span class="n">p</span> <span class="bp">∈</span> <span class="n">primes</span><span class="o">,</span> <span class="o">{</span> <span class="n">x</span> <span class="bp">|</span> <span class="bp">¬</span><span class="n">p</span> <span class="bp">∣</span> <span class="n">x</span> <span class="o">})</span> <span class="bp">⊆</span> <span class="o">{</span> <span class="n">x</span> <span class="bp">|</span> <span class="n">x</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">}</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">contrapose</span><span class="bp">!</span> <span class="n">simp</span> <span class="n">apply</span> <span class="n">Nat.exists_prime_and_dvd</span> </pre></div> </div> <p>Try solving the following example, which is similar. If you start typing <code class="docutils literal notranslate"><span class="pre">eq_univ</span></code>, tab completion will tell you that <code class="docutils literal notranslate"><span class="pre">apply</span> <span class="pre">eq_univ_of_forall</span></code> is a good way to start the proof. We also recommend using the theorem <code class="docutils literal notranslate"><span class="pre">Nat.exists_infinite_primes</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="bp">⋃</span> <span class="n">p</span> <span class="bp">∈</span> <span class="n">primes</span><span class="o">,</span> <span class="o">{</span> <span class="n">x</span> <span class="bp">|</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">p</span> <span class="o">})</span> <span class="bp">=</span> <span class="n">univ</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Give a collection of sets, <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">:</span> <span class="pre">Set</span> <span class="pre">(Set</span> <span class="pre">α)</span></code>, their union, <code class="docutils literal notranslate"><span class="pre">⋃₀</span> <span class="pre">s</span></code>, has type <code class="docutils literal notranslate"><span class="pre">Set</span> <span class="pre">α</span></code> and is defined as <code class="docutils literal notranslate"><span class="pre">{x</span> <span class="pre">|</span> <span class="pre">∃</span> <span class="pre">t</span> <span class="pre">∈</span> <span class="pre">s,</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">t}</span></code>. Similarly, their intersection, <code class="docutils literal notranslate"><span class="pre">⋂₀</span> <span class="pre">s</span></code>, is defined as <code class="docutils literal notranslate"><span class="pre">{x</span> <span class="pre">|</span> <span class="pre">∀</span> <span class="pre">t</span> <span class="pre">∈</span> <span class="pre">s,</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">t}</span></code>. These operations are called <code class="docutils literal notranslate"><span class="pre">sUnion</span></code> and <code class="docutils literal notranslate"><span class="pre">sInter</span></code>, respectively. The following examples show their relationship to bounded union and intersection.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">(</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="o">(</span><span class="n">Set</span> <span class="n">α</span><span class="o">))</span> <span class="kd">example</span> <span class="o">:</span> <span class="bp">⋃₀</span> <span class="n">s</span> <span class="bp">=</span> <span class="bp">⋃</span> <span class="n">t</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="n">t</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ext</span> <span class="n">x</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mem_iUnion₂</span><span class="o">]</span> <span class="n">simp</span> <span class="kd">example</span> <span class="o">:</span> <span class="bp">⋂₀</span> <span class="n">s</span> <span class="bp">=</span> <span class="bp">⋂</span> <span class="n">t</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="n">t</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ext</span> <span class="n">x</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mem_iInter₂</span><span class="o">]</span> <span class="n">rfl</span> </pre></div> </div> <p>In the library, these identities are called <code class="docutils literal notranslate"><span class="pre">sUnion_eq_biUnion</span></code> and <code class="docutils literal notranslate"><span class="pre">sInter_eq_biInter</span></code>.</p> </section> <section id="functions"> <span id="id3"></span><h2><span class="section-number">4.2. </span>Functions<a class="headerlink" href="#functions" title="Permalink to this heading"></a></h2> <p>If <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">α</span> <span class="pre">→</span> <span class="pre">β</span></code> is a function and <code class="docutils literal notranslate"><span class="pre">p</span></code> is a set of elements of type <code class="docutils literal notranslate"><span class="pre">β</span></code>, the library defines <code class="docutils literal notranslate"><span class="pre">preimage</span> <span class="pre">f</span> <span class="pre">p</span></code>, written <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">⁻¹'</span> <span class="pre">p</span></code>, to be <code class="docutils literal notranslate"><span class="pre">{x</span> <span class="pre">|</span> <span class="pre">f</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">p}</span></code>. The expression <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">∈</span> <span class="pre">f</span> <span class="pre">⁻¹'</span> <span class="pre">p</span></code> reduces to <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">p</span></code>. This is often convenient, as in the following example:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="n">β</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">β</span><span class="o">)</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">s</span> <span class="n">t</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">α</span><span class="o">)</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">u</span> <span class="n">v</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">β</span><span class="o">)</span> <span class="kn">open</span> <span class="n">Function</span> <span class="kn">open</span> <span class="n">Set</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="o">(</span><span class="n">u</span> <span class="bp">∩</span> <span class="n">v</span><span class="o">)</span> <span class="bp">=</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">u</span> <span class="bp">∩</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">v</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ext</span> <span class="n">rfl</span> </pre></div> </div> <p>If <code class="docutils literal notranslate"><span class="pre">s</span></code> is a set of elements of type <code class="docutils literal notranslate"><span class="pre">α</span></code>, the library also defines <code class="docutils literal notranslate"><span class="pre">image</span> <span class="pre">f</span> <span class="pre">s</span></code>, written <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">''</span> <span class="pre">s</span></code>, to be <code class="docutils literal notranslate"><span class="pre">{y</span> <span class="pre">|</span> <span class="pre">∃</span> <span class="pre">x,</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span> <span class="pre">∧</span> <span class="pre">f</span> <span class="pre">x</span> <span class="pre">=</span> <span class="pre">y}</span></code>. So a hypothesis <code class="docutils literal notranslate"><span class="pre">y</span> <span class="pre">∈</span> <span class="pre">f</span> <span class="pre">''</span> <span class="pre">s</span></code> decomposes to a triple <code class="docutils literal notranslate"><span class="pre">⟨x,</span> <span class="pre">xs,</span> <span class="pre">xeq⟩</span></code> with <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">:</span> <span class="pre">α</span></code> satisfying the hypotheses <code class="docutils literal notranslate"><span class="pre">xs</span> <span class="pre">:</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span></code> and <code class="docutils literal notranslate"><span class="pre">xeq</span> <span class="pre">:</span> <span class="pre">f</span> <span class="pre">x</span> <span class="pre">=</span> <span class="pre">y</span></code>. The <code class="docutils literal notranslate"><span class="pre">rfl</span></code> tag in the <code class="docutils literal notranslate"><span class="pre">rintro</span></code> tactic (see <a class="reference internal" href="C03_Logic.html#the-existential-quantifier"><span class="std std-numref">Section 3.2</span></a>) was made precisely for this sort of situation.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">''</span> <span class="o">(</span><span class="n">s</span> <span class="bp">∪</span> <span class="n">t</span><span class="o">)</span> <span class="bp">=</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">s</span> <span class="bp">∪</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">t</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ext</span> <span class="n">y</span><span class="bp">;</span> <span class="n">constructor</span> <span class="bp">·</span> <span class="n">rintro</span> <span class="o">⟨</span><span class="n">x</span><span class="o">,</span> <span class="n">xs</span> <span class="bp">|</span> <span class="n">xt</span><span class="o">,</span> <span class="n">rfl</span><span class="o">⟩</span> <span class="bp">·</span> <span class="n">left</span> <span class="n">use</span> <span class="n">x</span><span class="o">,</span> <span class="n">xs</span> <span class="n">right</span> <span class="n">use</span> <span class="n">x</span><span class="o">,</span> <span class="n">xt</span> <span class="n">rintro</span> <span class="o">(⟨</span><span class="n">x</span><span class="o">,</span> <span class="n">xs</span><span class="o">,</span> <span class="n">rfl</span><span class="o">⟩</span> <span class="bp">|</span> <span class="o">⟨</span><span class="n">x</span><span class="o">,</span> <span class="n">xt</span><span class="o">,</span> <span class="n">rfl</span><span class="o">⟩)</span> <span class="bp">·</span> <span class="n">use</span> <span class="n">x</span><span class="o">,</span> <span class="n">Or.inl</span> <span class="n">xs</span> <span class="n">use</span> <span class="n">x</span><span class="o">,</span> <span class="n">Or.inr</span> <span class="n">xt</span> </pre></div> </div> <p>Notice also that the <code class="docutils literal notranslate"><span class="pre">use</span></code> tactic applies <code class="docutils literal notranslate"><span class="pre">rfl</span></code> to close goals when it can.</p> <p>Here is another example:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="o">(</span><span class="n">f</span> <span class="bp">''</span> <span class="n">s</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">xs</span> <span class="k">show</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">s</span> <span class="n">use</span> <span class="n">x</span><span class="o">,</span> <span class="n">xs</span> </pre></div> </div> <p>We can replace the line <code class="docutils literal notranslate"><span class="pre">use</span> <span class="pre">x,</span> <span class="pre">xs</span></code> by <code class="docutils literal notranslate"><span class="pre">apply</span> <span class="pre">mem_image_of_mem</span> <span class="pre">f</span> <span class="pre">xs</span></code> if we want to use a theorem specifically designed for that purpose. But knowing that the image is defined in terms of an existential quantifier is often convenient.</p> <p>The following equivalence is a good exercise:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="n">v</span> <span class="bp">↔</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">v</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>It shows that <code class="docutils literal notranslate"><span class="pre">image</span> <span class="pre">f</span></code> and <code class="docutils literal notranslate"><span class="pre">preimage</span> <span class="pre">f</span></code> are an instance of what is known as a <em>Galois connection</em> between <code class="docutils literal notranslate"><span class="pre">Set</span> <span class="pre">α</span></code> and <code class="docutils literal notranslate"><span class="pre">Set</span> <span class="pre">β</span></code>, each partially ordered by the subset relation. In the library, this equivalence is named <code class="docutils literal notranslate"><span class="pre">image_subset_iff</span></code>. In practice, the right-hand side is often the more useful representation, because <code class="docutils literal notranslate"><span class="pre">y</span> <span class="pre">∈</span> <span class="pre">f</span> <span class="pre">⁻¹'</span> <span class="pre">t</span></code> unfolds to <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">y</span> <span class="pre">∈</span> <span class="pre">t</span></code> whereas working with <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">∈</span> <span class="pre">f</span> <span class="pre">''</span> <span class="pre">s</span></code> requires decomposing an existential quantifier.</p> <p>Here is a long list of set-theoretic identities for you to enjoy. You don’t have to do all of them at once; do a few of them, and set the rest aside for a rainy day.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">Injective</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="o">(</span><span class="n">f</span> <span class="bp">''</span> <span class="n">s</span><span class="o">)</span> <span class="bp">⊆</span> <span class="n">s</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">''</span> <span class="o">(</span><span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">u</span><span class="o">)</span> <span class="bp">⊆</span> <span class="n">u</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">Surjective</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">u</span> <span class="bp">⊆</span> <span class="n">f</span> <span class="bp">''</span> <span class="o">(</span><span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">u</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="n">t</span><span class="o">)</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">t</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">u</span> <span class="bp">⊆</span> <span class="n">v</span><span class="o">)</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">u</span> <span class="bp">⊆</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">v</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="o">(</span><span class="n">u</span> <span class="bp">∪</span> <span class="n">v</span><span class="o">)</span> <span class="bp">=</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">u</span> <span class="bp">∪</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">v</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">''</span> <span class="o">(</span><span class="n">s</span> <span class="bp">∩</span> <span class="n">t</span><span class="o">)</span> <span class="bp">⊆</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">t</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">Injective</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">t</span> <span class="bp">⊆</span> <span class="n">f</span> <span class="bp">''</span> <span class="o">(</span><span class="n">s</span> <span class="bp">∩</span> <span class="n">t</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">s</span> <span class="bp">\</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">t</span> <span class="bp">⊆</span> <span class="n">f</span> <span class="bp">''</span> <span class="o">(</span><span class="n">s</span> <span class="bp">\</span> <span class="n">t</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">u</span> <span class="bp">\</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">v</span> <span class="bp">⊆</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="o">(</span><span class="n">u</span> <span class="bp">\</span> <span class="n">v</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">v</span> <span class="bp">=</span> <span class="n">f</span> <span class="bp">''</span> <span class="o">(</span><span class="n">s</span> <span class="bp">∩</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">v</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">''</span> <span class="o">(</span><span class="n">s</span> <span class="bp">∩</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">u</span><span class="o">)</span> <span class="bp">⊆</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">s</span> <span class="bp">∪</span> <span class="n">u</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">u</span> <span class="bp">⊆</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="o">(</span><span class="n">f</span> <span class="bp">''</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">u</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∪</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">u</span> <span class="bp">⊆</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="o">(</span><span class="n">f</span> <span class="bp">''</span> <span class="n">s</span> <span class="bp">∪</span> <span class="n">u</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>You can also try your hand at the next group of exercises, which characterize the behavior of images and preimages with respect to indexed unions and intersections. In the third exercise, the argument <code class="docutils literal notranslate"><span class="pre">i</span> <span class="pre">:</span> <span class="pre">I</span></code> is needed to guarantee that the index set is nonempty. To prove any of these, we recommend using <code class="docutils literal notranslate"><span class="pre">ext</span></code> or <code class="docutils literal notranslate"><span class="pre">intro</span></code> to unfold the meaning of an equation or inclusion between sets, and then calling <code class="docutils literal notranslate"><span class="pre">simp</span></code> to unpack the conditions for membership.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">I</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">(</span><span class="n">A</span> <span class="o">:</span> <span class="n">I</span> <span class="bp">→</span> <span class="n">Set</span> <span class="n">α</span><span class="o">)</span> <span class="o">(</span><span class="n">B</span> <span class="o">:</span> <span class="n">I</span> <span class="bp">→</span> <span class="n">Set</span> <span class="n">β</span><span class="o">)</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">f</span> <span class="bp">''</span> <span class="bp">⋃</span> <span class="n">i</span><span class="o">,</span> <span class="n">A</span> <span class="n">i</span><span class="o">)</span> <span class="bp">=</span> <span class="bp">⋃</span> <span class="n">i</span><span class="o">,</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">A</span> <span class="n">i</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ext</span> <span class="n">y</span><span class="bp">;</span> <span class="n">simp</span> <span class="n">constructor</span> <span class="bp">·</span> <span class="n">rintro</span> <span class="o">⟨</span><span class="n">x</span><span class="o">,</span> <span class="o">⟨</span><span class="n">i</span><span class="o">,</span> <span class="n">xAi</span><span class="o">⟩,</span> <span class="n">fxeq</span><span class="o">⟩</span> <span class="n">use</span> <span class="n">i</span><span class="o">,</span> <span class="n">x</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">xAi</span><span class="o">,</span> <span class="n">fxeq</span><span class="o">⟩</span> <span class="n">rintro</span> <span class="o">⟨</span><span class="n">i</span><span class="o">,</span> <span class="n">x</span><span class="o">,</span> <span class="n">xAi</span><span class="o">,</span> <span class="n">fxeq</span><span class="o">⟩</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">x</span><span class="o">,</span> <span class="o">⟨</span><span class="n">i</span><span class="o">,</span> <span class="n">xAi</span><span class="o">⟩,</span> <span class="n">fxeq</span><span class="o">⟩</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">f</span> <span class="bp">''</span> <span class="bp">⋂</span> <span class="n">i</span><span class="o">,</span> <span class="n">A</span> <span class="n">i</span><span class="o">)</span> <span class="bp">⊆</span> <span class="bp">⋂</span> <span class="n">i</span><span class="o">,</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">A</span> <span class="n">i</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">y</span><span class="bp">;</span> <span class="n">simp</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">h</span> <span class="n">fxeq</span> <span class="n">i</span> <span class="n">use</span> <span class="n">x</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">h</span> <span class="n">i</span><span class="o">,</span> <span class="n">fxeq</span><span class="o">⟩</span> <span class="kd">example</span> <span class="o">(</span><span class="n">i</span> <span class="o">:</span> <span class="n">I</span><span class="o">)</span> <span class="o">(</span><span class="n">injf</span> <span class="o">:</span> <span class="n">Injective</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="bp">⋂</span> <span class="n">i</span><span class="o">,</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">A</span> <span class="n">i</span><span class="o">)</span> <span class="bp">⊆</span> <span class="n">f</span> <span class="bp">''</span> <span class="bp">⋂</span> <span class="n">i</span><span class="o">,</span> <span class="n">A</span> <span class="n">i</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">y</span><span class="bp">;</span> <span class="n">simp</span> <span class="n">intro</span> <span class="n">h</span> <span class="n">rcases</span> <span class="n">h</span> <span class="n">i</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">x</span><span class="o">,</span> <span class="n">xAi</span><span class="o">,</span> <span class="n">fxeq</span><span class="o">⟩</span> <span class="n">use</span> <span class="n">x</span><span class="bp">;</span> <span class="n">constructor</span> <span class="bp">·</span> <span class="n">intro</span> <span class="n">i'</span> <span class="n">rcases</span> <span class="n">h</span> <span class="n">i'</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">x'</span><span class="o">,</span> <span class="n">x'Ai</span><span class="o">,</span> <span class="n">fx'eq</span><span class="o">⟩</span> <span class="k">have</span> <span class="o">:</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">f</span> <span class="n">x'</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">fxeq</span><span class="o">,</span> <span class="n">fx'eq</span><span class="o">]</span> <span class="k">have</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">x'</span> <span class="o">:=</span> <span class="n">injf</span> <span class="n">this</span> <span class="n">rw</span> <span class="o">[</span><span class="n">this</span><span class="o">]</span> <span class="n">exact</span> <span class="n">x'Ai</span> <span class="n">exact</span> <span class="n">fxeq</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">f</span> <span class="bp">⁻¹'</span> <span class="bp">⋃</span> <span class="n">i</span><span class="o">,</span> <span class="n">B</span> <span class="n">i</span><span class="o">)</span> <span class="bp">=</span> <span class="bp">⋃</span> <span class="n">i</span><span class="o">,</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">B</span> <span class="n">i</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ext</span> <span class="n">x</span> <span class="n">simp</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">f</span> <span class="bp">⁻¹'</span> <span class="bp">⋂</span> <span class="n">i</span><span class="o">,</span> <span class="n">B</span> <span class="n">i</span><span class="o">)</span> <span class="bp">=</span> <span class="bp">⋂</span> <span class="n">i</span><span class="o">,</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">B</span> <span class="n">i</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ext</span> <span class="n">x</span> <span class="n">simp</span> </pre></div> </div> <p>The library defines a predicate <code class="docutils literal notranslate"><span class="pre">InjOn</span> <span class="pre">f</span> <span class="pre">s</span></code> to say that <code class="docutils literal notranslate"><span class="pre">f</span></code> is injective on <code class="docutils literal notranslate"><span class="pre">s</span></code>. It is defined as follows:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">InjOn</span> <span class="n">f</span> <span class="n">s</span> <span class="bp">↔</span> <span class="bp">∀</span> <span class="n">x₁</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">x₂</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="n">f</span> <span class="n">x₁</span> <span class="bp">=</span> <span class="n">f</span> <span class="n">x₂</span> <span class="bp">→</span> <span class="n">x₁</span> <span class="bp">=</span> <span class="n">x₂</span> <span class="o">:=</span> <span class="n">Iff.refl</span> <span class="n">_</span> </pre></div> </div> <p>The statement <code class="docutils literal notranslate"><span class="pre">Injective</span> <span class="pre">f</span></code> is provably equivalent to <code class="docutils literal notranslate"><span class="pre">InjOn</span> <span class="pre">f</span> <span class="pre">univ</span></code>. Similarly, the library defines <code class="docutils literal notranslate"><span class="pre">range</span> <span class="pre">f</span></code> to be <code class="docutils literal notranslate"><span class="pre">{x</span> <span class="pre">|</span> <span class="pre">∃y,</span> <span class="pre">f</span> <span class="pre">y</span> <span class="pre">=</span> <span class="pre">x}</span></code>, so <code class="docutils literal notranslate"><span class="pre">range</span> <span class="pre">f</span></code> is provably equal to <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">''</span> <span class="pre">univ</span></code>. This is a common theme in mathlib: although many properties of functions are defined relative to their full domain, there are often relativized versions that restrict the statements to a subset of the domain type.</p> <p>Here is are some examples of <code class="docutils literal notranslate"><span class="pre">InjOn</span></code> and <code class="docutils literal notranslate"><span class="pre">range</span></code> in use:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">open</span> <span class="n">Set</span> <span class="n">Real</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">InjOn</span> <span class="n">log</span> <span class="o">{</span> <span class="n">x</span> <span class="bp">|</span> <span class="n">x</span> <span class="bp">></span> <span class="mi">0</span> <span class="o">}</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">xpos</span> <span class="n">y</span> <span class="n">ypos</span> <span class="n">intro</span> <span class="n">e</span> <span class="c1">-- log x = log y</span> <span class="k">calc</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">exp</span> <span class="o">(</span><span class="n">log</span> <span class="n">x</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">exp_log</span> <span class="n">xpos</span><span class="o">]</span> <span class="n">_</span> <span class="bp">=</span> <span class="n">exp</span> <span class="o">(</span><span class="n">log</span> <span class="n">y</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">e</span><span class="o">]</span> <span class="n">_</span> <span class="bp">=</span> <span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">exp_log</span> <span class="n">ypos</span><span class="o">]</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">range</span> <span class="n">exp</span> <span class="bp">=</span> <span class="o">{</span> <span class="n">y</span> <span class="bp">|</span> <span class="n">y</span> <span class="bp">></span> <span class="mi">0</span> <span class="o">}</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ext</span> <span class="n">y</span><span class="bp">;</span> <span class="n">constructor</span> <span class="bp">·</span> <span class="n">rintro</span> <span class="o">⟨</span><span class="n">x</span><span class="o">,</span> <span class="n">rfl</span><span class="o">⟩</span> <span class="n">apply</span> <span class="n">exp_pos</span> <span class="n">intro</span> <span class="n">ypos</span> <span class="n">use</span> <span class="n">log</span> <span class="n">y</span> <span class="n">rw</span> <span class="o">[</span><span class="n">exp_log</span> <span class="n">ypos</span><span class="o">]</span> </pre></div> </div> <p>Try proving these:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">InjOn</span> <span class="n">sqrt</span> <span class="o">{</span> <span class="n">x</span> <span class="bp">|</span> <span class="n">x</span> <span class="bp">≥</span> <span class="mi">0</span> <span class="o">}</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">InjOn</span> <span class="o">(</span><span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span><span class="o">)</span> <span class="o">{</span> <span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">|</span> <span class="n">x</span> <span class="bp">≥</span> <span class="mi">0</span> <span class="o">}</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">sqrt</span> <span class="bp">''</span> <span class="o">{</span> <span class="n">x</span> <span class="bp">|</span> <span class="n">x</span> <span class="bp">≥</span> <span class="mi">0</span> <span class="o">}</span> <span class="bp">=</span> <span class="o">{</span> <span class="n">y</span> <span class="bp">|</span> <span class="n">y</span> <span class="bp">≥</span> <span class="mi">0</span> <span class="o">}</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">range</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span><span class="o">)</span> <span class="bp">=</span> <span class="o">{</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">|</span> <span class="n">y</span> <span class="bp">≥</span> <span class="mi">0</span> <span class="o">}</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>To define the inverse of a function <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">α</span> <span class="pre">→</span> <span class="pre">β</span></code>, we will use two new ingredients. First, we need to deal with the fact that an arbitrary type in Lean may be empty. To define the inverse to <code class="docutils literal notranslate"><span class="pre">f</span></code> at <code class="docutils literal notranslate"><span class="pre">y</span></code> when there is no <code class="docutils literal notranslate"><span class="pre">x</span></code> satisfying <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span> <span class="pre">=</span> <span class="pre">y</span></code>, we want to assign a default value in <code class="docutils literal notranslate"><span class="pre">α</span></code>. Adding the annotation <code class="docutils literal notranslate"><span class="pre">[Inhabited</span> <span class="pre">α]</span></code> as a variable is tantamount to assuming that <code class="docutils literal notranslate"><span class="pre">α</span></code> has a preferred element, which is denoted <code class="docutils literal notranslate"><span class="pre">default</span></code>. Second, in the case where there is more than one <code class="docutils literal notranslate"><span class="pre">x</span></code> such that <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span> <span class="pre">=</span> <span class="pre">y</span></code>, the inverse function needs to <em>choose</em> one of them. This requires an appeal to the <em>axiom of choice</em>. Lean allows various ways of accessing it; one convenient method is to use the classical <code class="docutils literal notranslate"><span class="pre">some</span></code> operator, illustrated below.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="n">β</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">Inhabited</span> <span class="n">α</span><span class="o">]</span> <span class="k">#check</span> <span class="o">(</span><span class="n">default</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">P</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="kt">Prop</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span><span class="o">,</span> <span class="n">P</span> <span class="n">x</span><span class="o">)</span> <span class="k">#check</span> <span class="n">Classical.choose</span> <span class="n">h</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">P</span> <span class="o">(</span><span class="n">Classical.choose</span> <span class="n">h</span><span class="o">)</span> <span class="o">:=</span> <span class="n">Classical.choose_spec</span> <span class="n">h</span> </pre></div> </div> <p>Given <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">:</span> <span class="pre">∃</span> <span class="pre">x,</span> <span class="pre">P</span> <span class="pre">x</span></code>, the value of <code class="docutils literal notranslate"><span class="pre">Classical.some</span> <span class="pre">h</span></code> is some <code class="docutils literal notranslate"><span class="pre">x</span></code> satisfying <code class="docutils literal notranslate"><span class="pre">P</span> <span class="pre">x</span></code>. The theorem <code class="docutils literal notranslate"><span class="pre">Classical.some_spec</span> <span class="pre">h</span></code> says that <code class="docutils literal notranslate"><span class="pre">Classical.some</span> <span class="pre">h</span></code> meets this specification.</p> <p>With these in hand, we can define the inverse function as follows:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">noncomputable</span> <span class="kn">section</span> <span class="kn">open</span> <span class="n">Classical</span> <span class="kd">def</span> <span class="n">inverse</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">β</span><span class="o">)</span> <span class="o">:</span> <span class="n">β</span> <span class="bp">→</span> <span class="n">α</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">y</span> <span class="o">:</span> <span class="n">β</span> <span class="bp">=></span> <span class="k">if</span> <span class="n">h</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">y</span> <span class="k">then</span> <span class="n">Classical.choose</span> <span class="n">h</span> <span class="k">else</span> <span class="n">default</span> <span class="kd">theorem</span> <span class="n">inverse_spec</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">β</span><span class="o">}</span> <span class="o">(</span><span class="n">y</span> <span class="o">:</span> <span class="n">β</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">y</span><span class="o">)</span> <span class="o">:</span> <span class="n">f</span> <span class="o">(</span><span class="n">inverse</span> <span class="n">f</span> <span class="n">y</span><span class="o">)</span> <span class="bp">=</span> <span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">inverse</span><span class="o">]</span><span class="bp">;</span> <span class="n">dsimp</span><span class="bp">;</span> <span class="n">rw</span> <span class="o">[</span><span class="n">dif_pos</span> <span class="n">h</span><span class="o">]</span> <span class="n">exact</span> <span class="n">Classical.choose_spec</span> <span class="n">h</span> </pre></div> </div> <p>The lines <code class="docutils literal notranslate"><span class="pre">noncomputable</span> <span class="pre">theory</span></code> and <code class="docutils literal notranslate"><span class="pre">open</span> <span class="pre">Classical</span></code> are needed because we are using classical logic in an essential way. On input <code class="docutils literal notranslate"><span class="pre">y</span></code>, the function <code class="docutils literal notranslate"><span class="pre">inverse</span> <span class="pre">f</span></code> returns some value of <code class="docutils literal notranslate"><span class="pre">x</span></code> satisfying <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span> <span class="pre">=</span> <span class="pre">y</span></code> if there is one, and a default element of <code class="docutils literal notranslate"><span class="pre">α</span></code> otherwise. This is an instance of a <em>dependent if</em> construction, since in the positive case, the value returned, <code class="docutils literal notranslate"><span class="pre">Classical.choose</span> <span class="pre">h</span></code>, depends on the assumption <code class="docutils literal notranslate"><span class="pre">h</span></code>. The identity <code class="docutils literal notranslate"><span class="pre">dif_pos</span> <span class="pre">h</span></code> rewrites <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">h</span> <span class="pre">:</span> <span class="pre">e</span> <span class="pre">then</span> <span class="pre">a</span> <span class="pre">else</span> <span class="pre">b</span></code> to <code class="docutils literal notranslate"><span class="pre">a</span></code> given <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">:</span> <span class="pre">e</span></code>, and, similarly, <code class="docutils literal notranslate"><span class="pre">dif_neg</span> <span class="pre">h</span></code> rewrites it to <code class="docutils literal notranslate"><span class="pre">b</span></code> given <code class="docutils literal notranslate"><span class="pre">h</span> <span class="pre">:</span> <span class="pre">¬</span> <span class="pre">e</span></code>. The theorem <code class="docutils literal notranslate"><span class="pre">inverse_spec</span></code> says that <code class="docutils literal notranslate"><span class="pre">inverse</span> <span class="pre">f</span></code> meets the first part of this specification.</p> <p>Don’t worry if you do not fully understand how these work. The theorem <code class="docutils literal notranslate"><span class="pre">inverse_spec</span></code> alone should be enough to show that <code class="docutils literal notranslate"><span class="pre">inverse</span> <span class="pre">f</span></code> is a left inverse if and only if <code class="docutils literal notranslate"><span class="pre">f</span></code> is injective and a right inverse if and only if <code class="docutils literal notranslate"><span class="pre">f</span></code> is surjective. Look up the definition of <code class="docutils literal notranslate"><span class="pre">LeftInverse</span></code> and <code class="docutils literal notranslate"><span class="pre">RightInverse</span></code> by double-clicking or right-clicking on them in VS Code, or using the commands <code class="docutils literal notranslate"><span class="pre">#print</span> <span class="pre">LeftInverse</span></code> and <code class="docutils literal notranslate"><span class="pre">#print</span> <span class="pre">RightInverse</span></code>. Then try to prove the two theorems. They are tricky! It helps to do the proofs on paper before you start hacking through the details. You should be able to prove each of them with about a half-dozen short lines. If you are looking for an extra challenge, try to condense each proof to a single-line proof term.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">β</span><span class="o">)</span> <span class="kn">open</span> <span class="n">Function</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">Injective</span> <span class="n">f</span> <span class="bp">↔</span> <span class="n">LeftInverse</span> <span class="o">(</span><span class="n">inverse</span> <span class="n">f</span><span class="o">)</span> <span class="n">f</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">Surjective</span> <span class="n">f</span> <span class="bp">↔</span> <span class="n">RightInverse</span> <span class="o">(</span><span class="n">inverse</span> <span class="n">f</span><span class="o">)</span> <span class="n">f</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>We close this section with a type-theoretic statement of Cantor’s famous theorem that there is no surjective function from a set to its power set. See if you can understand the proof, and then fill in the two lines that are missing.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">Cantor</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">f</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">Set</span> <span class="n">α</span><span class="o">,</span> <span class="bp">¬</span><span class="n">Surjective</span> <span class="n">f</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">f</span> <span class="n">surjf</span> <span class="k">let</span> <span class="n">S</span> <span class="o">:=</span> <span class="o">{</span> <span class="n">i</span> <span class="bp">|</span> <span class="n">i</span> <span class="bp">∉</span> <span class="n">f</span> <span class="n">i</span> <span class="o">}</span> <span class="n">rcases</span> <span class="n">surjf</span> <span class="n">S</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">j</span><span class="o">,</span> <span class="n">h</span><span class="o">⟩</span> <span class="k">have</span> <span class="n">h₁</span> <span class="o">:</span> <span class="n">j</span> <span class="bp">∉</span> <span class="n">f</span> <span class="n">j</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">h'</span> <span class="k">have</span> <span class="o">:</span> <span class="n">j</span> <span class="bp">∉</span> <span class="n">f</span> <span class="n">j</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rwa</span> <span class="o">[</span><span class="n">h</span><span class="o">]</span> <span class="n">at</span> <span class="n">h'</span> <span class="n">contradiction</span> <span class="k">have</span> <span class="n">h₂</span> <span class="o">:</span> <span class="n">j</span> <span class="bp">∈</span> <span class="n">S</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="n">h₃</span> <span class="o">:</span> <span class="n">j</span> <span class="bp">∉</span> <span class="n">S</span> <span class="gr">sorry</span> <span class="n">contradiction</span> </pre></div> </div> </section> <section id="the-schroder-bernstein-theorem"> <span id="the-schroeder-bernstein-theorem"></span><h2><span class="section-number">4.3. </span>The Schröder-Bernstein Theorem<a class="headerlink" href="#the-schroder-bernstein-theorem" title="Permalink to this heading"></a></h2> <p>We close this chapter with an elementary but nontrivial theorem of set theory. Let <span class="math notranslate nohighlight">\(\alpha\)</span> and <span class="math notranslate nohighlight">\(\beta\)</span> be sets. (In our formalization, they will actually be types.) Suppose <span class="math notranslate nohighlight">\(f : \alpha → \beta\)</span> and <span class="math notranslate nohighlight">\(g : \beta → \alpha\)</span> are both injective. Intuitively, this means that <span class="math notranslate nohighlight">\(\alpha\)</span> is no bigger than <span class="math notranslate nohighlight">\(\beta\)</span> and vice-versa. If <span class="math notranslate nohighlight">\(\alpha\)</span> and <span class="math notranslate nohighlight">\(\beta\)</span> are finite, this implies that they have the same cardinality, which is equivalent to saying that there is a bijection between them. In the nineteenth century, Cantor stated that same result holds even in the case where <span class="math notranslate nohighlight">\(\alpha\)</span> and <span class="math notranslate nohighlight">\(\beta\)</span> are infinite. This was eventually established by Dedekind, Schröder, and Bernstein independently.</p> <p>Our formalization will introduce some new methods that we will explain in greater detail in chapters to come. Don’t worry if they go by too quickly here. Our goal is to show you that you already have the skills to contribute to the formal proof of a real mathematical result.</p> <p>To understand the idea behind the proof, consider the image of the map <span class="math notranslate nohighlight">\(g\)</span> in <span class="math notranslate nohighlight">\(\alpha\)</span>. On that image, the inverse of <span class="math notranslate nohighlight">\(g\)</span> is defined and is a bijection with <span class="math notranslate nohighlight">\(\beta\)</span>.</p> <a class="reference internal image-reference" href="_images/schroeder_bernstein1.png"><img alt="the Schröder Bernstein theorem" class="align-center" src="_images/schroeder_bernstein1.png" style="height: 150px;" /></a> <p>The problem is that the bijection does not include the shaded region in the diagram, which is nonempty if <span class="math notranslate nohighlight">\(g\)</span> is not surjective. Alternatively, we can use <span class="math notranslate nohighlight">\(f\)</span> to map all of <span class="math notranslate nohighlight">\(\alpha\)</span> to <span class="math notranslate nohighlight">\(\beta\)</span>, but in that case the problem is that if <span class="math notranslate nohighlight">\(f\)</span> is not surjective, it will miss some elements of <span class="math notranslate nohighlight">\(\beta\)</span>.</p> <a class="reference internal image-reference" href="_images/schroeder_bernstein2.png"><img alt="the Schröder Bernstein theorem" class="align-center" src="_images/schroeder_bernstein2.png" style="height: 150px;" /></a> <p>But now consider the composition <span class="math notranslate nohighlight">\(g \circ f\)</span> from <span class="math notranslate nohighlight">\(\alpha\)</span> to itself. Because the composition is injective, it forms a bijection between <span class="math notranslate nohighlight">\(\alpha\)</span> and its image, yielding a scaled-down copy of <span class="math notranslate nohighlight">\(\alpha\)</span> inside itself.</p> <a class="reference internal image-reference" href="_images/schroeder_bernstein3.png"><img alt="the Schröder Bernstein theorem" class="align-center" src="_images/schroeder_bernstein3.png" style="height: 150px;" /></a> <p>This composition maps the inner shaded ring to yet another such set, which we can think of as an even smaller concentric shaded ring, and so on. This yields a concentric sequence of shaded rings, each of which is in bijective correspondence with the next. If we map each ring to the next and leave the unshaded parts of <span class="math notranslate nohighlight">\(\alpha\)</span> alone, we have a bijection of <span class="math notranslate nohighlight">\(\alpha\)</span> with the image of <span class="math notranslate nohighlight">\(g\)</span>. Composing with <span class="math notranslate nohighlight">\(g^{-1}\)</span>, this yields the desired bijection between <span class="math notranslate nohighlight">\(\alpha\)</span> and <span class="math notranslate nohighlight">\(\beta\)</span>.</p> <p>We can describe this bijection more simply. Let <span class="math notranslate nohighlight">\(A\)</span> be the union of the sequence of shaded regions, and define <span class="math notranslate nohighlight">\(h : \alpha \to \beta\)</span> as follows:</p> <div class="math notranslate nohighlight"> \[\begin{split}h(x) = \begin{cases} f(x) & \text{if $x \in A$} \\ g^{-1}(x) & \text{otherwise.} \end{cases}\end{split}\]</div> <p>In other words, we use <span class="math notranslate nohighlight">\(f\)</span> on the shaded parts, and we use the inverse of <span class="math notranslate nohighlight">\(g\)</span> everywhere else. The resulting map <span class="math notranslate nohighlight">\(h\)</span> is injective because each component is injective and the images of the two components are disjoint. To see that it is surjective, suppose we are given a <span class="math notranslate nohighlight">\(y\)</span> in <span class="math notranslate nohighlight">\(\beta\)</span>, and consider <span class="math notranslate nohighlight">\(g(y)\)</span>. If <span class="math notranslate nohighlight">\(g(y)\)</span> is in one of the shaded regions, it cannot be in the first ring, so we have <span class="math notranslate nohighlight">\(g(y) = g(f(x))\)</span> for some <span class="math notranslate nohighlight">\(x\)</span> is in the previous ring. By the injectivity of <span class="math notranslate nohighlight">\(g\)</span>, we have <span class="math notranslate nohighlight">\(h(x) = f(x) = y\)</span>. If <span class="math notranslate nohighlight">\(g(y)\)</span> is not in the shaded region, then by the definition of <span class="math notranslate nohighlight">\(h\)</span>, we have <span class="math notranslate nohighlight">\(h(g(y))= y\)</span>. Either way, <span class="math notranslate nohighlight">\(y\)</span> is in the image of <span class="math notranslate nohighlight">\(h\)</span>.</p> <p>This argument should sound plausible, but the details are delicate. Formalizing the proof will not only improve our confidence in the result, but also help us understand it better. Because the proof uses classical logic, we tell Lean that our definitions will generally not be computable.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">noncomputable</span> <span class="kn">section</span> <span class="kn">open</span> <span class="n">Classical</span> <span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="n">β</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">Nonempty</span> <span class="n">β</span><span class="o">]</span> </pre></div> </div> <p>The annotation <code class="docutils literal notranslate"><span class="pre">[Nonempty</span> <span class="pre">β]</span></code> specifies that <code class="docutils literal notranslate"><span class="pre">β</span></code> is nonempty. We use it because the mathlib primitive that we will use to construct <span class="math notranslate nohighlight">\(g^{-1}\)</span> requires it. The case of the theorem where <span class="math notranslate nohighlight">\(\beta\)</span> is empty is trivial, and even though it would not be hard to generalize the formalization to cover that case as well, we will not bother. Specifically, we need the hypothesis <code class="docutils literal notranslate"><span class="pre">[Nonempty</span> <span class="pre">β]</span></code> for the operation <code class="docutils literal notranslate"><span class="pre">invFun</span></code> that is defined in mathlib. Given <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">:</span> <span class="pre">α</span></code>, <code class="docutils literal notranslate"><span class="pre">invFun</span> <span class="pre">g</span> <span class="pre">x</span></code> chooses a preimage of <code class="docutils literal notranslate"><span class="pre">x</span></code> in <code class="docutils literal notranslate"><span class="pre">β</span></code> if there is one, and returns an arbitrary element of <code class="docutils literal notranslate"><span class="pre">β</span></code> otherwise. The function <code class="docutils literal notranslate"><span class="pre">invFun</span> <span class="pre">g</span></code> is always a left inverse if <code class="docutils literal notranslate"><span class="pre">g</span></code> is injective and a right inverse if <code class="docutils literal notranslate"><span class="pre">g</span></code> is surjective.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="o">(</span><span class="n">invFun</span> <span class="n">g</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">β</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">leftInverse_invFun</span> <span class="o">:</span> <span class="n">Injective</span> <span class="n">g</span> <span class="bp">→</span> <span class="n">LeftInverse</span> <span class="o">(</span><span class="n">invFun</span> <span class="n">g</span><span class="o">)</span> <span class="n">g</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">leftInverse_invFun</span> <span class="o">:</span> <span class="n">Injective</span> <span class="n">g</span> <span class="bp">→</span> <span class="bp">∀</span> <span class="n">y</span><span class="o">,</span> <span class="n">invFun</span> <span class="n">g</span> <span class="o">(</span><span class="n">g</span> <span class="n">y</span><span class="o">)</span> <span class="bp">=</span> <span class="n">y</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">invFun_eq</span> <span class="o">:</span> <span class="o">(</span><span class="bp">∃</span> <span class="n">y</span><span class="o">,</span> <span class="n">g</span> <span class="n">y</span> <span class="bp">=</span> <span class="n">x</span><span class="o">)</span> <span class="bp">→</span> <span class="n">g</span> <span class="o">(</span><span class="n">invFun</span> <span class="n">g</span> <span class="n">x</span><span class="o">)</span> <span class="bp">=</span> <span class="n">x</span><span class="o">)</span> </pre></div> </div> <p>We define the set corresponding to the union of the shaded regions as follows.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">β</span><span class="o">)</span> <span class="o">(</span><span class="n">g</span> <span class="o">:</span> <span class="n">β</span> <span class="bp">→</span> <span class="n">α</span><span class="o">)</span> <span class="kd">def</span> <span class="n">sbAux</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">Set</span> <span class="n">α</span> <span class="bp">|</span> <span class="mi">0</span> <span class="bp">=></span> <span class="n">univ</span> <span class="bp">\</span> <span class="n">g</span> <span class="bp">''</span> <span class="n">univ</span> <span class="bp">|</span> <span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span> <span class="bp">=></span> <span class="n">g</span> <span class="bp">''</span> <span class="o">(</span><span class="n">f</span> <span class="bp">''</span> <span class="n">sbAux</span> <span class="n">n</span><span class="o">)</span> <span class="kd">def</span> <span class="n">sbSet</span> <span class="o">:=</span> <span class="bp">⋃</span> <span class="n">n</span><span class="o">,</span> <span class="n">sbAux</span> <span class="n">f</span> <span class="n">g</span> <span class="n">n</span> </pre></div> </div> <p>The definition <code class="docutils literal notranslate"><span class="pre">sb_aux</span></code> is an example of a <em>recursive definition</em>, which we will explain in the next chapter. It defines a sequence of sets</p> <div class="math notranslate nohighlight"> \[\begin{split}S_0 &= \alpha ∖ g(\beta) \\ S_{n+1} &= g(f(S_n)).\end{split}\]</div> <p>The definition <code class="docutils literal notranslate"><span class="pre">sb_set</span></code> corresponds to the set <span class="math notranslate nohighlight">\(A = \bigcup_{n \in \mathbb{N}} S_n\)</span> in our proof sketch. The function <span class="math notranslate nohighlight">\(h\)</span> described above is now defined as follows:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">sbFun</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="o">:</span> <span class="n">β</span> <span class="o">:=</span> <span class="k">if</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">sbSet</span> <span class="n">f</span> <span class="n">g</span> <span class="k">then</span> <span class="n">f</span> <span class="n">x</span> <span class="k">else</span> <span class="n">invFun</span> <span class="n">g</span> <span class="n">x</span> </pre></div> </div> <p>We will need the fact that our definition of <span class="math notranslate nohighlight">\(g^{-1}\)</span> is a right inverse on the complement of <span class="math notranslate nohighlight">\(A\)</span>, which is to say, on the non-shaded regions of <span class="math notranslate nohighlight">\(\alpha\)</span>. This is so because the outermost ring, <span class="math notranslate nohighlight">\(S_0\)</span>, is equal to <span class="math notranslate nohighlight">\(\alpha \setminus g(\beta)\)</span>, so the complement of <span class="math notranslate nohighlight">\(A\)</span> is contained in <span class="math notranslate nohighlight">\(g(\beta)\)</span>. As a result, for every <span class="math notranslate nohighlight">\(x\)</span> in the complement of <span class="math notranslate nohighlight">\(A\)</span>, there is a <span class="math notranslate nohighlight">\(y\)</span> such that <span class="math notranslate nohighlight">\(g(y) = x\)</span>. (By the injectivity of <span class="math notranslate nohighlight">\(g\)</span>, this <span class="math notranslate nohighlight">\(y\)</span> is unique, but next theorem says only that <code class="docutils literal notranslate"><span class="pre">inv_fun</span> <span class="pre">g</span> <span class="pre">x</span></code> returns some <code class="docutils literal notranslate"><span class="pre">y</span></code> such that <code class="docutils literal notranslate"><span class="pre">g</span> <span class="pre">y</span> <span class="pre">=</span> <span class="pre">x</span></code>.)</p> <p>Step through the proof below, make sure you understand what is going on, and fill in the remaining parts. You will need to use <code class="docutils literal notranslate"><span class="pre">inv_fun_eq</span></code> at the end. Notice that rewriting with <code class="docutils literal notranslate"><span class="pre">sb_aux</span></code> here replaces <code class="docutils literal notranslate"><span class="pre">sb_aux</span> <span class="pre">f</span> <span class="pre">g</span> <span class="pre">0</span></code> with the right-hand side of the corresponding defining equation.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">sb_right_inv</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">α</span><span class="o">}</span> <span class="o">(</span><span class="n">hx</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∉</span> <span class="n">sbSet</span> <span class="n">f</span> <span class="n">g</span><span class="o">)</span> <span class="o">:</span> <span class="n">g</span> <span class="o">(</span><span class="n">invFun</span> <span class="n">g</span> <span class="n">x</span><span class="o">)</span> <span class="bp">=</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="k">have</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">g</span> <span class="bp">''</span> <span class="n">univ</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">contrapose</span><span class="bp">!</span> <span class="n">hx</span> <span class="n">rw</span> <span class="o">[</span><span class="n">sbSet</span><span class="o">,</span> <span class="n">mem_iUnion</span><span class="o">]</span> <span class="n">use</span> <span class="mi">0</span> <span class="n">rw</span> <span class="o">[</span><span class="n">sbAux</span><span class="o">,</span> <span class="n">mem_diff</span><span class="o">]</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">y</span><span class="o">,</span> <span class="n">g</span> <span class="n">y</span> <span class="bp">=</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="gr">sorry</span> </pre></div> </div> <p>We now turn to the proof that <span class="math notranslate nohighlight">\(h\)</span> is injective. Informally, the proof goes as follows. First, suppose <span class="math notranslate nohighlight">\(h(x_1) = h(x_2)\)</span>. If <span class="math notranslate nohighlight">\(x_1\)</span> is in <span class="math notranslate nohighlight">\(A\)</span>, then <span class="math notranslate nohighlight">\(h(x_1) = f(x_1)\)</span>, and we can show that <span class="math notranslate nohighlight">\(x_2\)</span> is in <span class="math notranslate nohighlight">\(A\)</span> as follows. If it isn’t, then we have <span class="math notranslate nohighlight">\(h(x_2) = g^{-1}(x_2)\)</span>. From <span class="math notranslate nohighlight">\(f(x_1) = h(x_1) = h(x_2)\)</span> we have <span class="math notranslate nohighlight">\(g(f(x_1)) = x_2\)</span>. From the definition of <span class="math notranslate nohighlight">\(A\)</span>, since <span class="math notranslate nohighlight">\(x_1\)</span> is in <span class="math notranslate nohighlight">\(A\)</span>, <span class="math notranslate nohighlight">\(x_2\)</span> is in <span class="math notranslate nohighlight">\(A\)</span> as well, a contradiction. Hence, if <span class="math notranslate nohighlight">\(x_1\)</span> is in <span class="math notranslate nohighlight">\(A\)</span>, so is <span class="math notranslate nohighlight">\(x_2\)</span>, in which case we have <span class="math notranslate nohighlight">\(f(x_1) = h(x_1) = h(x_2) = f(x_2)\)</span>. The injectivity of <span class="math notranslate nohighlight">\(f\)</span> then implies <span class="math notranslate nohighlight">\(x_1 = x_2\)</span>. The symmetric argument shows that if <span class="math notranslate nohighlight">\(x_2\)</span> is in <span class="math notranslate nohighlight">\(A\)</span>, then so is <span class="math notranslate nohighlight">\(x_1\)</span>, which again implies <span class="math notranslate nohighlight">\(x_1 = x_2\)</span>.</p> <p>The only remaining possibility is that neither <span class="math notranslate nohighlight">\(x_1\)</span> nor <span class="math notranslate nohighlight">\(x_2\)</span> is in <span class="math notranslate nohighlight">\(A\)</span>. In that case, we have <span class="math notranslate nohighlight">\(g^{-1}(x_1) = h(x_1) = h(x_2) = g^{-1}(x_2)\)</span>. Applying <span class="math notranslate nohighlight">\(g\)</span> to both sides yields <span class="math notranslate nohighlight">\(x_1 = x_2\)</span>.</p> <p>Once again, we encourage you to step through the following proof to see how the argument plays out in Lean. See if you can finish off the proof using <code class="docutils literal notranslate"><span class="pre">sb_right_inv</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">sb_injective</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">Injective</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">hg</span> <span class="o">:</span> <span class="n">Injective</span> <span class="n">g</span><span class="o">)</span> <span class="o">:</span> <span class="n">Injective</span> <span class="o">(</span><span class="n">sbFun</span> <span class="n">f</span> <span class="n">g</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">set</span> <span class="n">A</span> <span class="o">:=</span> <span class="n">sbSet</span> <span class="n">f</span> <span class="n">g</span> <span class="k">with</span> <span class="n">A_def</span> <span class="n">set</span> <span class="n">h</span> <span class="o">:=</span> <span class="n">sbFun</span> <span class="n">f</span> <span class="n">g</span> <span class="k">with</span> <span class="n">h_def</span> <span class="n">intro</span> <span class="n">x₁</span> <span class="n">x₂</span> <span class="n">intro</span> <span class="o">(</span><span class="n">hxeq</span> <span class="o">:</span> <span class="n">h</span> <span class="n">x₁</span> <span class="bp">=</span> <span class="n">h</span> <span class="n">x₂</span><span class="o">)</span> <span class="k">show</span> <span class="n">x₁</span> <span class="bp">=</span> <span class="n">x₂</span> <span class="n">simp</span> <span class="n">only</span> <span class="o">[</span><span class="n">h_def</span><span class="o">,</span> <span class="n">sbFun</span><span class="o">,</span> <span class="bp">←</span> <span class="n">A_def</span><span class="o">]</span> <span class="n">at</span> <span class="n">hxeq</span> <span class="n">by_cases</span> <span class="n">xA</span> <span class="o">:</span> <span class="n">x₁</span> <span class="bp">∈</span> <span class="n">A</span> <span class="bp">∨</span> <span class="n">x₂</span> <span class="bp">∈</span> <span class="n">A</span> <span class="bp">·</span> <span class="n">wlog</span> <span class="n">x₁A</span> <span class="o">:</span> <span class="n">x₁</span> <span class="bp">∈</span> <span class="n">A</span> <span class="n">generalizing</span> <span class="n">x₁</span> <span class="n">x₂</span> <span class="n">hxeq</span> <span class="n">xA</span> <span class="bp">·</span> <span class="n">symm</span> <span class="n">apply</span> <span class="n">this</span> <span class="n">hxeq.symm</span> <span class="n">xA.symm</span> <span class="o">(</span><span class="n">xA.resolve_left</span> <span class="n">x₁A</span><span class="o">)</span> <span class="k">have</span> <span class="n">x₂A</span> <span class="o">:</span> <span class="n">x₂</span> <span class="bp">∈</span> <span class="n">A</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">not_imp_self.mp</span> <span class="n">intro</span> <span class="o">(</span><span class="n">x₂nA</span> <span class="o">:</span> <span class="n">x₂</span> <span class="bp">∉</span> <span class="n">A</span><span class="o">)</span> <span class="n">rw</span> <span class="o">[</span><span class="n">if_pos</span> <span class="n">x₁A</span><span class="o">,</span> <span class="n">if_neg</span> <span class="n">x₂nA</span><span class="o">]</span> <span class="n">at</span> <span class="n">hxeq</span> <span class="n">rw</span> <span class="o">[</span><span class="n">A_def</span><span class="o">,</span> <span class="n">sbSet</span><span class="o">,</span> <span class="n">mem_iUnion</span><span class="o">]</span> <span class="n">at</span> <span class="n">x₁A</span> <span class="k">have</span> <span class="n">x₂eq</span> <span class="o">:</span> <span class="n">x₂</span> <span class="bp">=</span> <span class="n">g</span> <span class="o">(</span><span class="n">f</span> <span class="n">x₁</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="n">rcases</span> <span class="n">x₁A</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">n</span><span class="o">,</span> <span class="n">hn</span><span class="o">⟩</span> <span class="n">rw</span> <span class="o">[</span><span class="n">A_def</span><span class="o">,</span> <span class="n">sbSet</span><span class="o">,</span> <span class="n">mem_iUnion</span><span class="o">]</span> <span class="n">use</span> <span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span> <span class="n">simp</span> <span class="o">[</span><span class="n">sbAux</span><span class="o">]</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">x₁</span><span class="o">,</span> <span class="n">hn</span><span class="o">,</span> <span class="n">x₂eq.symm</span><span class="o">⟩</span> <span class="gr">sorry</span> <span class="n">push_neg</span> <span class="n">at</span> <span class="n">xA</span> <span class="gr">sorry</span> </pre></div> </div> <p>The proof introduces some new tactics. To start with, notice the <code class="docutils literal notranslate"><span class="pre">set</span></code> tactic, which introduces abbreviations <code class="docutils literal notranslate"><span class="pre">A</span></code> and <code class="docutils literal notranslate"><span class="pre">h</span></code> for <code class="docutils literal notranslate"><span class="pre">sb_set</span> <span class="pre">f</span> <span class="pre">g</span></code> and <code class="docutils literal notranslate"><span class="pre">sb_fun</span> <span class="pre">f</span> <span class="pre">g</span></code> respectively. We name the corresponding defining equations <code class="docutils literal notranslate"><span class="pre">A_def</span></code> and <code class="docutils literal notranslate"><span class="pre">h_def</span></code>. The abbreviations are definitional, which is to say, Lean will sometimes unfold them automatically when needed. But not always; for example, when using <code class="docutils literal notranslate"><span class="pre">rw</span></code>, we generally need to use <code class="docutils literal notranslate"><span class="pre">A_def</span></code> and <code class="docutils literal notranslate"><span class="pre">h_def</span></code> explicitly. So the definitions bring a tradeoff: they can make expressions shorter and more readable, but they sometimes require us to do more work.</p> <p>A more interesting tactic is the <code class="docutils literal notranslate"><span class="pre">wlog</span></code> tactic, which encapsulates the symmetry argument in the informal proof above. We will not dwell on it now, but notice that it does exactly what we want. If you hover over the tactic you can take a look at its documentation.</p> <p>The argument for surjectivity is even easier. Given <span class="math notranslate nohighlight">\(y\)</span> in <span class="math notranslate nohighlight">\(\beta\)</span>, we consider two cases, depending on whether <span class="math notranslate nohighlight">\(g(y)\)</span> is in <span class="math notranslate nohighlight">\(A\)</span>. If it is, it can’t be in <span class="math notranslate nohighlight">\(S_0\)</span>, the outermost ring, because by definition that is disjoint from the image of <span class="math notranslate nohighlight">\(g\)</span>. Thus it is an element of <span class="math notranslate nohighlight">\(S_{n+1}\)</span> for some <span class="math notranslate nohighlight">\(n\)</span>. This means that it is of the form <span class="math notranslate nohighlight">\(g(f(x))\)</span> for some <span class="math notranslate nohighlight">\(x\)</span> in <span class="math notranslate nohighlight">\(S_n\)</span>. By the injectivity of <span class="math notranslate nohighlight">\(g\)</span>, we have <span class="math notranslate nohighlight">\(f(x) = y\)</span>. In the case where <span class="math notranslate nohighlight">\(g(y)\)</span> is in the complement of <span class="math notranslate nohighlight">\(A\)</span>, we immediately have <span class="math notranslate nohighlight">\(h(g(y))= y\)</span>, and we are done.</p> <p>Once again, we encourage you to step through the proof and fill in the missing parts. The tactic <code class="docutils literal notranslate"><span class="pre">cases</span> <span class="pre">n</span> <span class="pre">with</span> <span class="pre">n</span></code> splits on the cases <code class="docutils literal notranslate"><span class="pre">g</span> <span class="pre">y</span> <span class="pre">∈</span> <span class="pre">sb_aux</span> <span class="pre">f</span> <span class="pre">g</span> <span class="pre">0</span></code> and <code class="docutils literal notranslate"><span class="pre">g</span> <span class="pre">y</span> <span class="pre">∈</span> <span class="pre">sb_aux</span> <span class="pre">f</span> <span class="pre">g</span> <span class="pre">n.succ</span></code>. In both cases, calling the simplifier with <code class="docutils literal notranslate"><span class="pre">simp</span> <span class="pre">[sb_aux]</span></code> applies the corresponding defining equation of <code class="docutils literal notranslate"><span class="pre">sb_aux</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">sb_surjective</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">Injective</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">hg</span> <span class="o">:</span> <span class="n">Injective</span> <span class="n">g</span><span class="o">)</span> <span class="o">:</span> <span class="n">Surjective</span> <span class="o">(</span><span class="n">sbFun</span> <span class="n">f</span> <span class="n">g</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">set</span> <span class="n">A</span> <span class="o">:=</span> <span class="n">sbSet</span> <span class="n">f</span> <span class="n">g</span> <span class="k">with</span> <span class="n">A_def</span> <span class="n">set</span> <span class="n">h</span> <span class="o">:=</span> <span class="n">sbFun</span> <span class="n">f</span> <span class="n">g</span> <span class="k">with</span> <span class="n">h_def</span> <span class="n">intro</span> <span class="n">y</span> <span class="n">by_cases</span> <span class="n">gyA</span> <span class="o">:</span> <span class="n">g</span> <span class="n">y</span> <span class="bp">∈</span> <span class="n">A</span> <span class="bp">·</span> <span class="n">rw</span> <span class="o">[</span><span class="n">A_def</span><span class="o">,</span> <span class="n">sbSet</span><span class="o">,</span> <span class="n">mem_iUnion</span><span class="o">]</span> <span class="n">at</span> <span class="n">gyA</span> <span class="n">rcases</span> <span class="n">gyA</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">n</span><span class="o">,</span> <span class="n">hn</span><span class="o">⟩</span> <span class="n">cases'</span> <span class="n">n</span> <span class="k">with</span> <span class="n">n</span> <span class="bp">·</span> <span class="n">simp</span> <span class="o">[</span><span class="n">sbAux</span><span class="o">]</span> <span class="n">at</span> <span class="n">hn</span> <span class="n">simp</span> <span class="o">[</span><span class="n">sbAux</span><span class="o">]</span> <span class="n">at</span> <span class="n">hn</span> <span class="n">rcases</span> <span class="n">hn</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">x</span><span class="o">,</span> <span class="n">xmem</span><span class="o">,</span> <span class="n">hx</span><span class="o">⟩</span> <span class="n">use</span> <span class="n">x</span> <span class="k">have</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">A</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">A_def</span><span class="o">,</span> <span class="n">sbSet</span><span class="o">,</span> <span class="n">mem_iUnion</span><span class="o">]</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">n</span><span class="o">,</span> <span class="n">xmem</span><span class="o">⟩</span> <span class="n">simp</span> <span class="n">only</span> <span class="o">[</span><span class="n">h_def</span><span class="o">,</span> <span class="n">sbFun</span><span class="o">,</span> <span class="n">if_pos</span> <span class="n">this</span><span class="o">]</span> <span class="n">exact</span> <span class="n">hg</span> <span class="n">hx</span> <span class="gr">sorry</span> </pre></div> </div> <p>We can now put it all together. The final statement is short and sweet, and the proof uses the fact that <code class="docutils literal notranslate"><span class="pre">Bijective</span> <span class="pre">h</span></code> unfolds to <code class="docutils literal notranslate"><span class="pre">Injective</span> <span class="pre">h</span> <span class="pre">∧</span> <span class="pre">Surjective</span> <span class="pre">h</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">schroeder_bernstein</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">β</span><span class="o">}</span> <span class="o">{</span><span class="n">g</span> <span class="o">:</span> <span class="n">β</span> <span class="bp">→</span> <span class="n">α</span><span class="o">}</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">Injective</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">hg</span> <span class="o">:</span> <span class="n">Injective</span> <span class="n">g</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">h</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">β</span><span class="o">,</span> <span class="n">Bijective</span> <span class="n">h</span> <span class="o">:=</span> <span class="o">⟨</span><span class="n">sbFun</span> <span class="n">f</span> <span class="n">g</span><span class="o">,</span> <span class="n">sb_injective</span> <span class="n">f</span> <span class="n">g</span> <span class="n">hf</span> <span class="n">hg</span><span class="o">,</span> <span class="n">sb_surjective</span> <span class="n">f</span> <span class="n">g</span> <span class="n">hf</span> <span class="n">hg</span><span class="o">⟩</span> </pre></div> </div> </section> </section> </div> </div> <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> <a href="C03_Logic.html" class="btn btn-neutral float-left" title="3. Logic" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> <a href="C05_Number_Theory.html" class="btn btn-neutral float-right" title="5. Number Theory" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> </div> <hr/> <div role="contentinfo"> <p>© Copyright 2020, Jeremy Avigad, Kevin Buzzard, Robert Y. Lewis, Patrick Massot.</p> </div> Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. </footer> </div> </div> </section> </div> <script> jQuery(function () { SphinxRtdTheme.Navigation.enable(true); }); </script> </body> </html>
-
-
-
@@ -0,0 +1,1180 @@<!DOCTYPE html> <html class="writer-html5" lang="en" > <head> <meta charset="utf-8" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>5. Number Theory — Mathematics in Lean 0.1 documentation</title> <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> <link rel="stylesheet" href="_static/css/custom.css" type="text/css" /> <link rel="shortcut icon" href="_static/favicon.ico"/> <!--[if lt IE 9]> <script src="_static/js/html5shiv.min.js"></script> <![endif]--> <script src="_static/jquery.js"></script> <script src="_static/_sphinx_javascript_frameworks_compat.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script src="_static/doctools.js"></script> <script src="_static/sphinx_highlight.js"></script> <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> <script src="_static/js/theme.js"></script> <link rel="index" title="Index" href="genindex.html" /> <link rel="search" title="Search" href="search.html" /> <link rel="next" title="6. Structures" href="C06_Structures.html" /> <link rel="prev" title="4. Sets and Functions" href="C04_Sets_and_Functions.html" /> </head> <body class="wy-body-for-nav"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search" > <a href="index.html" class="icon icon-home"> Mathematics in Lean </a> <div role="search"> <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> <ul class="current"> <li class="toctree-l1"><a class="reference internal" href="C01_Introduction.html">1. Introduction</a></li> <li class="toctree-l1"><a class="reference internal" href="C02_Basics.html">2. Basics</a></li> <li class="toctree-l1"><a class="reference internal" href="C03_Logic.html">3. Logic</a></li> <li class="toctree-l1"><a class="reference internal" href="C04_Sets_and_Functions.html">4. Sets and Functions</a></li> <li class="toctree-l1 current"><a class="current reference internal" href="#">5. Number Theory</a><ul> <li class="toctree-l2"><a class="reference internal" href="#irrational-roots">5.1. Irrational Roots</a></li> <li class="toctree-l2"><a class="reference internal" href="#induction-and-recursion">5.2. Induction and Recursion</a></li> <li class="toctree-l2"><a class="reference internal" href="#infinitely-many-primes">5.3. Infinitely Many Primes</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="C06_Structures.html">6. Structures</a></li> <li class="toctree-l1"><a class="reference internal" href="C07_Hierarchies.html">7. Hierarchies</a></li> <li class="toctree-l1"><a class="reference internal" href="C08_Topology.html">8. Topology</a></li> <li class="toctree-l1"><a class="reference internal" href="C09_Differential_Calculus.html">9. Differential Calculus</a></li> </ul> <ul> <li class="toctree-l1"><a class="reference internal" href="genindex.html">Index</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="index.html">Mathematics in Lean</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="Page navigation"> <ul class="wy-breadcrumbs"> <li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li> <li class="breadcrumb-item active"><span class="section-number">5. </span>Number Theory</li> <li class="wy-breadcrumbs-aside"> <a href="_sources/C05_Number_Theory.rst.txt" rel="nofollow"> View page source</a> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <section id="number-theory"> <span id="id1"></span><h1><span class="section-number">5. </span>Number Theory<a class="headerlink" href="#number-theory" title="Permalink to this heading"></a></h1> <p>In this chapter, we show you how to formalize some elementary results in number theory. As we deal with more substantive mathematical content, the proofs will get longer and more involved, building on the skills you have already mastered.</p> <section id="irrational-roots"> <span id="section-irrational-roots"></span><h2><span class="section-number">5.1. </span>Irrational Roots<a class="headerlink" href="#irrational-roots" title="Permalink to this heading"></a></h2> <p>Let’s start with a fact known to the ancient greeks, namely, that the square root of 2 is irrational. If we suppose otherwise, we can write <span class="math notranslate nohighlight">\(\sqrt{2} = a / b\)</span> as a fraction in lowest terms. Squaring both sides yields <span class="math notranslate nohighlight">\(a^2 = 2 b^2\)</span>, which implies that <span class="math notranslate nohighlight">\(a\)</span> is even. If we write <span class="math notranslate nohighlight">\(a = 2c\)</span>, then we get <span class="math notranslate nohighlight">\(4c^2 = 2 b^2\)</span> and hence <span class="math notranslate nohighlight">\(b^2 = 2 c^2\)</span>. This implies that <span class="math notranslate nohighlight">\(b\)</span> is also even, contradicting the fact that we have assumed that <span class="math notranslate nohighlight">\(a / b\)</span> has been reduced to lowest terms.</p> <p>Saying that <span class="math notranslate nohighlight">\(a / b\)</span> is a fraction in lowest terms means that <span class="math notranslate nohighlight">\(a\)</span> and <span class="math notranslate nohighlight">\(b\)</span> do not have any factors in common, which is to say, they are <em>coprime</em>. Mathlib defines the predicate <code class="docutils literal notranslate"><span class="pre">Nat.coprime</span> <span class="pre">m</span> <span class="pre">n</span></code> to be <code class="docutils literal notranslate"><span class="pre">Nat.gcd</span> <span class="pre">m</span> <span class="pre">n</span> <span class="pre">=</span> <span class="pre">1</span></code>. Using Lean’s anonymous projection notation, if <code class="docutils literal notranslate"><span class="pre">s</span></code> and <code class="docutils literal notranslate"><span class="pre">t</span></code> are expressions of type <code class="docutils literal notranslate"><span class="pre">Nat</span></code>, we can write <code class="docutils literal notranslate"><span class="pre">s.coprime</span> <span class="pre">t</span></code> instead of <code class="docutils literal notranslate"><span class="pre">Nat.coprime</span> <span class="pre">s</span> <span class="pre">t</span></code>, and similarly for <code class="docutils literal notranslate"><span class="pre">Nat.gcd</span></code>. As usual, Lean will often unfold the definition of <code class="docutils literal notranslate"><span class="pre">Nat.coprime</span></code> automatically when necessary, but we can also do it manually by rewriting or simplifying with the identifier <code class="docutils literal notranslate"><span class="pre">Nat.coprime</span></code>. The <code class="docutils literal notranslate"><span class="pre">norm_num</span></code> tactic is smart enough to compute concrete values.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#print</span> <span class="n">Nat.coprime</span> <span class="kd">example</span> <span class="o">(</span><span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">Nat</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">m.coprime</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="n">m.gcd</span> <span class="n">n</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">:=</span> <span class="n">h</span> <span class="kd">example</span> <span class="o">(</span><span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">Nat</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">m.coprime</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="n">m.gcd</span> <span class="n">n</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">Nat.coprime</span><span class="o">]</span> <span class="n">at</span> <span class="n">h</span> <span class="n">exact</span> <span class="n">h</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">Nat.coprime</span> <span class="mi">12</span> <span class="mi">7</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">norm_num</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">Nat.gcd</span> <span class="mi">12</span> <span class="mi">8</span> <span class="bp">=</span> <span class="mi">4</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">norm_num</span> </pre></div> </div> <p>We have already encountered the <code class="docutils literal notranslate"><span class="pre">gcd</span></code> function in <a class="reference internal" href="C02_Basics.html#more-on-order-and-divisibility"><span class="std std-numref">Section 2.4</span></a>. There is also a version of <code class="docutils literal notranslate"><span class="pre">gcd</span></code> for the integers; we will return to a discussion of the relationship between different number systems below. There are even a generic <code class="docutils literal notranslate"><span class="pre">gcd</span></code> function and generic notions of <code class="docutils literal notranslate"><span class="pre">Prime</span></code> and <code class="docutils literal notranslate"><span class="pre">coprime</span></code> that make sense in general classes of algebraic structures. We will come to understand how Lean manages this generality in the next chapter. In the meanwhile, in this section, we will restrict attention to the natural numbers.</p> <p>We also need the notion of a prime number, <code class="docutils literal notranslate"><span class="pre">Nat.Prime</span></code>. The theorem <code class="docutils literal notranslate"><span class="pre">Nat.prime_def_lt</span></code> provides one familiar characterization, and <code class="docutils literal notranslate"><span class="pre">Nat.Prime.eq_one_or_self_of_dvd</span></code> provides another.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="bp">@</span><span class="n">Nat.prime_def_lt</span> <span class="kd">example</span> <span class="o">(</span><span class="n">p</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">prime_p</span> <span class="o">:</span> <span class="n">Nat.Prime</span> <span class="n">p</span><span class="o">)</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">≤</span> <span class="n">p</span> <span class="bp">∧</span> <span class="bp">∀</span> <span class="n">m</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">,</span> <span class="n">m</span> <span class="bp"><</span> <span class="n">p</span> <span class="bp">→</span> <span class="n">m</span> <span class="bp">∣</span> <span class="n">p</span> <span class="bp">→</span> <span class="n">m</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rwa</span> <span class="o">[</span><span class="n">Nat.prime_def_lt</span><span class="o">]</span> <span class="n">at</span> <span class="n">prime_p</span> <span class="k">#check</span> <span class="n">Nat.Prime.eq_one_or_self_of_dvd</span> <span class="kd">example</span> <span class="o">(</span><span class="n">p</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">prime_p</span> <span class="o">:</span> <span class="n">Nat.Prime</span> <span class="n">p</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">m</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">,</span> <span class="n">m</span> <span class="bp">∣</span> <span class="n">p</span> <span class="bp">→</span> <span class="n">m</span> <span class="bp">=</span> <span class="mi">1</span> <span class="bp">∨</span> <span class="n">m</span> <span class="bp">=</span> <span class="n">p</span> <span class="o">:=</span> <span class="n">prime_p.eq_one_or_self_of_dvd</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">Nat.Prime</span> <span class="mi">17</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">norm_num</span> <span class="c1">-- commonly used</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">Nat.Prime</span> <span class="mi">2</span> <span class="o">:=</span> <span class="n">Nat.prime_two</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">Nat.Prime</span> <span class="mi">3</span> <span class="o">:=</span> <span class="n">Nat.prime_three</span> </pre></div> </div> <p>In the natural numbers, a prime number has the property that it cannot be written as a product of nontrivial factors. In a broader mathematical context, an element of a ring that has this property is said to be <em>irreducible</em>. An element of a ring is said to be <em>prime</em> if whenever it divides a product, it divides one of the factors. It is an important property of the natural numbers that in that setting the two notions coincide, giving rise to the theorem <code class="docutils literal notranslate"><span class="pre">Nat.Prime.dvd_mul</span></code>.</p> <p>We can use this fact to establish a key property in the argument above: if the square of a number is even, then that number is even as well. Mathlib defines the predicate <code class="docutils literal notranslate"><span class="pre">Even</span></code> in <code class="docutils literal notranslate"><span class="pre">Data.Nat.Parity</span></code>, but for reasons that will become clear below, we will simply use <code class="docutils literal notranslate"><span class="pre">2</span> <span class="pre">∣</span> <span class="pre">m</span></code> to express that <code class="docutils literal notranslate"><span class="pre">m</span></code> is even.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="bp">@</span><span class="n">Nat.Prime.dvd_mul</span> <span class="k">#check</span> <span class="n">Nat.Prime.dvd_mul</span> <span class="n">Nat.prime_two</span> <span class="k">#check</span> <span class="n">Nat.prime_two.dvd_mul</span> <span class="kd">theorem</span> <span class="n">even_of_even_sqr</span> <span class="o">{</span><span class="n">m</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">∣</span> <span class="n">m</span> <span class="bp">^</span> <span class="mi">2</span><span class="o">)</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">∣</span> <span class="n">m</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">pow_two</span><span class="o">,</span> <span class="n">Nat.prime_two.dvd_mul</span><span class="o">]</span> <span class="n">at</span> <span class="n">h</span> <span class="n">cases</span> <span class="n">h</span> <span class="bp"><;></span> <span class="n">assumption</span> <span class="kd">example</span> <span class="o">{</span><span class="n">m</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">∣</span> <span class="n">m</span> <span class="bp">^</span> <span class="mi">2</span><span class="o">)</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">∣</span> <span class="n">m</span> <span class="o">:=</span> <span class="n">Nat.Prime.dvd_of_dvd_pow</span> <span class="n">Nat.prime_two</span> <span class="n">h</span> </pre></div> </div> <p>As we proceed, you will need to become proficient at finding the facts you need. Remember that if you can guess the prefix of the name and you have imported the relevant library, you can use tab completion (sometimes with <code class="docutils literal notranslate"><span class="pre">ctrl-tab</span></code>) to find what you are looking for. You can use <code class="docutils literal notranslate"><span class="pre">ctrl-click</span></code> on any identifier to jump to the file where it is defined, which enables you to browse definitions and theorems nearby. You can also use the search engine on the <a class="reference external" href="https://leanprover-community.github.io/">Lean community web pages</a>, and if all else fails, don’t hesitate to ask on <a class="reference external" href="https://leanprover.zulipchat.com/">Zulip</a>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">Nat</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">c</span><span class="o">)</span> <span class="o">(</span><span class="n">h'</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">≠</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">c</span> <span class="o">:=</span> <span class="c1">-- library_search suggests the following:</span> <span class="o">(</span><span class="n">mul_right_inj'</span> <span class="n">h'</span><span class="o">)</span><span class="bp">.</span><span class="n">mp</span> <span class="n">h</span> </pre></div> </div> <p>The heart of our proof of the irrationality of the square root of two is contained in the following theorem. See if you can fill out the proof sketch, using <code class="docutils literal notranslate"><span class="pre">even_of_even_sqr</span></code> and the theorem <code class="docutils literal notranslate"><span class="pre">Nat.dvd_gcd</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">coprime_mn</span> <span class="o">:</span> <span class="n">m.coprime</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">≠</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">n</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">sqr_eq</span> <span class="k">have</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">∣</span> <span class="n">m</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="n">obtain</span> <span class="o">⟨</span><span class="n">k</span><span class="o">,</span> <span class="n">meq</span><span class="o">⟩</span> <span class="o">:=</span> <span class="n">dvd_iff_exists_eq_mul_left.mp</span> <span class="n">this</span> <span class="k">have</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">*</span> <span class="o">(</span><span class="mi">2</span> <span class="bp">*</span> <span class="n">k</span> <span class="bp">^</span> <span class="mi">2</span><span class="o">)</span> <span class="bp">=</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">n</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="bp">←</span> <span class="n">sqr_eq</span><span class="o">,</span> <span class="n">meq</span><span class="o">]</span> <span class="n">ring</span> <span class="k">have</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">k</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">=</span> <span class="n">n</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">∣</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">∣</span> <span class="n">m.gcd</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">∣</span> <span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="n">norm_num</span> <span class="n">at</span> <span class="n">this</span> </pre></div> </div> <p>In fact, with very few changes, we can replace <code class="docutils literal notranslate"><span class="pre">2</span></code> by an arbitrary prime. Give it a try in the next example. At the end of the proof, you’ll need to derive a contradiction from <code class="docutils literal notranslate"><span class="pre">p</span> <span class="pre">∣</span> <span class="pre">1</span></code>. You can use <code class="docutils literal notranslate"><span class="pre">Nat.Prime.two_le</span></code>, which says that any prime number is greater than or equal to two, and <code class="docutils literal notranslate"><span class="pre">Nat.le_of_dvd</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">m</span> <span class="n">n</span> <span class="n">p</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">coprime_mn</span> <span class="o">:</span> <span class="n">m.coprime</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">prime_p</span> <span class="o">:</span> <span class="n">p.Prime</span><span class="o">)</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">≠</span> <span class="n">p</span> <span class="bp">*</span> <span class="n">n</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Let us consider another approach. Here is a quick proof that if <span class="math notranslate nohighlight">\(p\)</span> is prime, then <span class="math notranslate nohighlight">\(m^2 \ne p n^2\)</span>: if we assume <span class="math notranslate nohighlight">\(m^2 = p n^2\)</span> and consider the factorization of <span class="math notranslate nohighlight">\(m\)</span> and <span class="math notranslate nohighlight">\(n\)</span> into primes, then <span class="math notranslate nohighlight">\(p\)</span> occurs an even number of times on the left side of the equation and an odd number of times on the right, a contradiction. Note that this argument requires that <span class="math notranslate nohighlight">\(n\)</span> and hence <span class="math notranslate nohighlight">\(m\)</span> are not equal to zero. The formalization below confirms that this assumption is sufficient.</p> <p>The unique factorization theorem says that any natural number other than zero can be written as the product of primes in a unique way. Mathlib contains a formal version of this, expressed in terms of a function <code class="docutils literal notranslate"><span class="pre">Nat.factors</span></code>, which returns the list of prime factors of a number in nondecreasing order. The library proves that all the elements of <code class="docutils literal notranslate"><span class="pre">Nat.factors</span> <span class="pre">n</span></code> are prime, that any <code class="docutils literal notranslate"><span class="pre">n</span></code> greater than zero is equal to the product of its factors, and that if <code class="docutils literal notranslate"><span class="pre">n</span></code> is equal to the product of another list of prime numbers, then that list is a permutation of <code class="docutils literal notranslate"><span class="pre">Nat.factors</span> <span class="pre">n</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="n">Nat.factors</span> <span class="k">#check</span> <span class="n">Nat.prime_of_mem_factors</span> <span class="k">#check</span> <span class="n">Nat.prod_factors</span> <span class="k">#check</span> <span class="n">Nat.factors_unique</span> </pre></div> </div> <p>You can browse these theorems and others nearby, even though we have not talked about list membership, products, or permutations yet. We won’t need any of that for the task at hand. We will instead use the fact that Mathlib has a function <code class="docutils literal notranslate"><span class="pre">Nat.factorization</span></code>, that represents the same data as a function. Specifically, <code class="docutils literal notranslate"><span class="pre">Nat.factorization</span> <span class="pre">n</span> <span class="pre">p</span></code>, which we can also write <code class="docutils literal notranslate"><span class="pre">n.factorization</span> <span class="pre">p</span></code>, returns the multiplicity of <code class="docutils literal notranslate"><span class="pre">p</span></code> in the prime factorization of <code class="docutils literal notranslate"><span class="pre">n</span></code>. We will use the following three facts.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">factorization_mul'</span> <span class="o">{</span><span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">mnez</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">≠</span> <span class="mi">0</span><span class="o">)</span> <span class="o">(</span><span class="n">nnez</span> <span class="o">:</span> <span class="n">n</span> <span class="bp">≠</span> <span class="mi">0</span><span class="o">)</span> <span class="o">(</span><span class="n">p</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">m</span> <span class="bp">*</span> <span class="n">n</span><span class="o">)</span><span class="bp">.</span><span class="n">factorization</span> <span class="n">p</span> <span class="bp">=</span> <span class="n">m.factorization</span> <span class="n">p</span> <span class="bp">+</span> <span class="n">n.factorization</span> <span class="n">p</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">Nat.factorization_mul</span> <span class="n">mnez</span> <span class="n">nnez</span><span class="o">]</span> <span class="n">rfl</span> <span class="kd">theorem</span> <span class="n">factorization_pow'</span> <span class="o">(</span><span class="n">n</span> <span class="n">k</span> <span class="n">p</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">n</span> <span class="bp">^</span> <span class="n">k</span><span class="o">)</span><span class="bp">.</span><span class="n">factorization</span> <span class="n">p</span> <span class="bp">=</span> <span class="n">k</span> <span class="bp">*</span> <span class="n">n.factorization</span> <span class="n">p</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">Nat.factorization_pow</span><span class="o">]</span> <span class="n">rfl</span> <span class="kd">theorem</span> <span class="n">Nat.Prime.factorization'</span> <span class="o">{</span><span class="n">p</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">prime_p</span> <span class="o">:</span> <span class="n">p.Prime</span><span class="o">)</span> <span class="o">:</span> <span class="n">p.factorization</span> <span class="n">p</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">prime_p.factorization</span><span class="o">]</span> <span class="n">simp</span> </pre></div> </div> <p>In fact, <code class="docutils literal notranslate"><span class="pre">n.factorization</span></code> is defined in Lean as a function of finite support, which explains the strange notation you will see as you step through the proofs above. Don’t worry about this now. For our purposes here, we can use the three theorems above as a black box.</p> <p>The next example shows that the simplifier is smart enough to replace <code class="docutils literal notranslate"><span class="pre">n^2</span> <span class="pre">≠</span> <span class="pre">0</span></code> by <code class="docutils literal notranslate"><span class="pre">n</span> <span class="pre">≠</span> <span class="pre">0</span></code>. The tactic <code class="docutils literal notranslate"><span class="pre">simpa</span></code> just calls <code class="docutils literal notranslate"><span class="pre">simp</span></code> followed by <code class="docutils literal notranslate"><span class="pre">assumption</span></code>.</p> <p>See if you can use the identities above to fill in the missing parts of the proof.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">m</span> <span class="n">n</span> <span class="n">p</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">nnz</span> <span class="o">:</span> <span class="n">n</span> <span class="bp">≠</span> <span class="mi">0</span><span class="o">)</span> <span class="o">(</span><span class="n">prime_p</span> <span class="o">:</span> <span class="n">p.Prime</span><span class="o">)</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">≠</span> <span class="n">p</span> <span class="bp">*</span> <span class="n">n</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">sqr_eq</span> <span class="k">have</span> <span class="n">nsqr_nez</span> <span class="o">:</span> <span class="n">n</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">≠</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simpa</span> <span class="k">have</span> <span class="n">eq1</span> <span class="o">:</span> <span class="n">Nat.factorization</span> <span class="o">(</span><span class="n">m</span> <span class="bp">^</span> <span class="mi">2</span><span class="o">)</span> <span class="n">p</span> <span class="bp">=</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">m.factorization</span> <span class="n">p</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="n">eq2</span> <span class="o">:</span> <span class="o">(</span><span class="n">p</span> <span class="bp">*</span> <span class="n">n</span> <span class="bp">^</span> <span class="mi">2</span><span class="o">)</span><span class="bp">.</span><span class="n">factorization</span> <span class="n">p</span> <span class="bp">=</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">n.factorization</span> <span class="n">p</span> <span class="bp">+</span> <span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">m.factorization</span> <span class="n">p</span> <span class="bp">%</span> <span class="mi">2</span> <span class="bp">=</span> <span class="o">(</span><span class="mi">2</span> <span class="bp">*</span> <span class="n">n.factorization</span> <span class="n">p</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="bp">%</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="bp">←</span> <span class="n">eq1</span><span class="o">,</span> <span class="n">sqr_eq</span><span class="o">,</span> <span class="n">eq2</span><span class="o">]</span> <span class="n">rw</span> <span class="o">[</span><span class="n">add_comm</span><span class="o">,</span> <span class="n">Nat.add_mul_mod_self_left</span><span class="o">,</span> <span class="n">Nat.mul_mod_right</span><span class="o">]</span> <span class="n">at</span> <span class="n">this</span> <span class="n">norm_num</span> <span class="n">at</span> <span class="n">this</span> </pre></div> </div> <p>A nice thing about this proof is that it also generalizes. There is nothing special about <code class="docutils literal notranslate"><span class="pre">2</span></code>; with small changes, the proof shows that whenever we write <code class="docutils literal notranslate"><span class="pre">m^k</span> <span class="pre">=</span> <span class="pre">r</span> <span class="pre">*</span> <span class="pre">n^k</span></code>, the multiplicity of any prime <code class="docutils literal notranslate"><span class="pre">p</span></code> in <code class="docutils literal notranslate"><span class="pre">r</span></code> has to be a multiple of <code class="docutils literal notranslate"><span class="pre">k</span></code>.</p> <p>To use <code class="docutils literal notranslate"><span class="pre">Nat.count_factors_mul_of_pos</span></code> with <code class="docutils literal notranslate"><span class="pre">r</span> <span class="pre">*</span> <span class="pre">n^k</span></code>, we need to know that <code class="docutils literal notranslate"><span class="pre">r</span></code> is positive. But when <code class="docutils literal notranslate"><span class="pre">r</span></code> is zero, the theorem below is trivial, and easily proved by the simplifier. So the proof is carried out in cases. The line <code class="docutils literal notranslate"><span class="pre">cases</span> <span class="pre">r</span> <span class="pre">with</span> <span class="pre">r</span></code> replaces the goal with two versions: one in which <code class="docutils literal notranslate"><span class="pre">r</span></code> is replaced by <code class="docutils literal notranslate"><span class="pre">0</span></code>, and the other in which <code class="docutils literal notranslate"><span class="pre">r</span></code> is replaces by <code class="docutils literal notranslate"><span class="pre">r.succ</span></code>, the successor of <code class="docutils literal notranslate"><span class="pre">r</span></code>. In the second case, we can use the theorem <code class="docutils literal notranslate"><span class="pre">r.succ_ne_zero</span></code>, which establishes <code class="docutils literal notranslate"><span class="pre">r.succ</span> <span class="pre">≠</span> <span class="pre">0</span></code>.</p> <p>Notice also that the line that begins <code class="docutils literal notranslate"><span class="pre">have</span> <span class="pre">:</span> <span class="pre">npow_nz</span></code> provides a short proof-term proof of <code class="docutils literal notranslate"><span class="pre">n^k</span> <span class="pre">≠</span> <span class="pre">0</span></code>. To understand how it works, try replacing it with a tactic proof, and then think about how the tactics describe the proof term.</p> <p>See if you can fill in the missing parts of the proof below. At the very end, you can use <code class="docutils literal notranslate"><span class="pre">Nat.dvd_sub'</span></code> and <code class="docutils literal notranslate"><span class="pre">Nat.dvd_mul_right</span></code> to finish it off.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">m</span> <span class="n">n</span> <span class="n">k</span> <span class="n">r</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">nnz</span> <span class="o">:</span> <span class="n">n</span> <span class="bp">≠</span> <span class="mi">0</span><span class="o">)</span> <span class="o">(</span><span class="n">pow_eq</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">^</span> <span class="n">k</span> <span class="bp">=</span> <span class="n">r</span> <span class="bp">*</span> <span class="n">n</span> <span class="bp">^</span> <span class="n">k</span><span class="o">)</span> <span class="o">{</span><span class="n">p</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">prime_p</span> <span class="o">:</span> <span class="n">p.Prime</span><span class="o">)</span> <span class="o">:</span> <span class="n">k</span> <span class="bp">∣</span> <span class="n">r.factorization</span> <span class="n">p</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">cases'</span> <span class="n">r</span> <span class="k">with</span> <span class="n">r</span> <span class="bp">·</span> <span class="n">simp</span> <span class="k">have</span> <span class="n">npow_nz</span> <span class="o">:</span> <span class="n">n</span> <span class="bp">^</span> <span class="n">k</span> <span class="bp">≠</span> <span class="mi">0</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">npowz</span> <span class="bp">=></span> <span class="n">nnz</span> <span class="o">(</span><span class="n">pow_eq_zero</span> <span class="n">npowz</span><span class="o">)</span> <span class="k">have</span> <span class="n">eq1</span> <span class="o">:</span> <span class="o">(</span><span class="n">m</span> <span class="bp">^</span> <span class="n">k</span><span class="o">)</span><span class="bp">.</span><span class="n">factorization</span> <span class="n">p</span> <span class="bp">=</span> <span class="n">k</span> <span class="bp">*</span> <span class="n">m.factorization</span> <span class="n">p</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="n">eq2</span> <span class="o">:</span> <span class="o">(</span><span class="n">r.succ</span> <span class="bp">*</span> <span class="n">n</span> <span class="bp">^</span> <span class="n">k</span><span class="o">)</span><span class="bp">.</span><span class="n">factorization</span> <span class="n">p</span> <span class="bp">=</span> <span class="n">k</span> <span class="bp">*</span> <span class="n">n.factorization</span> <span class="n">p</span> <span class="bp">+</span> <span class="n">r.succ.factorization</span> <span class="n">p</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="o">:</span> <span class="n">r.succ.factorization</span> <span class="n">p</span> <span class="bp">=</span> <span class="n">k</span> <span class="bp">*</span> <span class="n">m.factorization</span> <span class="n">p</span> <span class="bp">-</span> <span class="n">k</span> <span class="bp">*</span> <span class="n">n.factorization</span> <span class="n">p</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="bp">←</span> <span class="n">eq1</span><span class="o">,</span> <span class="n">pow_eq</span><span class="o">,</span> <span class="n">eq2</span><span class="o">,</span> <span class="n">add_comm</span><span class="o">,</span> <span class="n">Nat.add_sub_cancel</span><span class="o">]</span> <span class="n">rw</span> <span class="o">[</span><span class="n">this</span><span class="o">]</span> <span class="gr">sorry</span> </pre></div> </div> <p>There are a number of ways in which we might want to improve on these results. To start with, a proof that the square root of two is irrational should say something about the square root of two, which can be understood as an element of the real or complex numbers. And stating that it is irrational should say something about the rational numbers, namely, that no rational number is equal to it. Moreover, we should extend the theorems in this section to the integers. Although it is mathematically obvious that if we could write the square root of two as a quotient of two integers then we could write it as a quotient of two natural numbers, proving this formally requires some effort.</p> <p>In Mathlib, the natural numbers, the integers, the rationals, the reals, and the complex numbers are represented by separate data types. Restricting attention to the separate domains is often helpful: we will see that it is easy to do induction on the natural numbers, and it is easiest to reason about divisibility of integers when the real numbers are not part of the picture. But having to mediate between the different domains is a headache, one we will have to contend with. We will return to this issue later in this chapter.</p> <p>We should also expect to be able to strengthen the conclusion of the last theorem to say that the number <code class="docutils literal notranslate"><span class="pre">r</span></code> is a <code class="docutils literal notranslate"><span class="pre">k</span></code>-th power, since its <code class="docutils literal notranslate"><span class="pre">k</span></code>-th root is just the product of each prime dividing <code class="docutils literal notranslate"><span class="pre">r</span></code> raised to its multiplicity in <code class="docutils literal notranslate"><span class="pre">r</span></code> divided by <code class="docutils literal notranslate"><span class="pre">k</span></code>. To be able to do that we will need better means for reasoning about products and sums over a finite set, which is also a topic we will return to.</p> <p>In fact, the results in this section are all established in much greater generality in mathlib, in <code class="docutils literal notranslate"><span class="pre">Data.Real.Irrational</span></code>. The notion of <code class="docutils literal notranslate"><span class="pre">multiplicity</span></code> is defined for an arbitrary commutative monoid, and that it takes values in the extended natural numbers <code class="docutils literal notranslate"><span class="pre">enat</span></code>, which adds the value infinity to the natural numbers. In the next chapter, we will begin to develop the means to appreciate the way that Lean supports this sort of generality.</p> </section> <section id="induction-and-recursion"> <span id="section-induction-and-recursion"></span><h2><span class="section-number">5.2. </span>Induction and Recursion<a class="headerlink" href="#induction-and-recursion" title="Permalink to this heading"></a></h2> <p>The set of natural numbers <span class="math notranslate nohighlight">\(\mathbb{N} = \{ 0, 1, 2, \ldots \}\)</span> is not only fundamentally important in its own right, but also a plays a central role in the construction of new mathematical objects. Lean’s foundation allows us to declare <em>inductive types</em>, which are types generated inductively by a given list of <em>constructors</em>. In Lean, the natural numbers are declared as follows.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">inductive</span> <span class="n">Nat</span> <span class="bp">|</span> <span class="n">zero</span> <span class="o">:</span> <span class="n">Nat</span> <span class="bp">|</span> <span class="n">succ</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">Nat</span><span class="o">)</span> <span class="o">:</span> <span class="n">Nat</span> </pre></div> </div> <p>You can find this in the library by writting <code class="docutils literal notranslate"><span class="pre">#check</span> <span class="pre">Nat</span></code> and then using <code class="docutils literal notranslate"><span class="pre">ctrl-click</span></code> on the identifier <code class="docutils literal notranslate"><span class="pre">Nat</span></code>. The command specifies that <code class="docutils literal notranslate"><span class="pre">Nat</span></code> is the datatype generated freely and inductively by the two constructors <code class="docutils literal notranslate"><span class="pre">zero</span> <span class="pre">:</span> <span class="pre">Nat</span></code> and <code class="docutils literal notranslate"><span class="pre">succ</span> <span class="pre">:</span> <span class="pre">Nat</span> <span class="pre">→</span> <span class="pre">Nat</span></code>. Of course, the library introduces notation <code class="docutils literal notranslate"><span class="pre">ℕ</span></code> and <code class="docutils literal notranslate"><span class="pre">0</span></code> for <code class="docutils literal notranslate"><span class="pre">nat</span></code> and <code class="docutils literal notranslate"><span class="pre">zero</span></code> respectively. (Numerals are translated to binary representations, but we don’t have to worry about the details of that now.)</p> <p>What “freely” means for the working mathematician is that the type <code class="docutils literal notranslate"><span class="pre">Nat</span></code> has an element <code class="docutils literal notranslate"><span class="pre">zero</span></code> and an injective successor function <code class="docutils literal notranslate"><span class="pre">succ</span></code> whose image does not include <code class="docutils literal notranslate"><span class="pre">zero</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">Nat</span><span class="o">)</span> <span class="o">:</span> <span class="n">n.succ</span> <span class="bp">≠</span> <span class="n">Nat.zero</span> <span class="o">:=</span> <span class="n">Nat.succ_ne_zero</span> <span class="n">n</span> <span class="kd">example</span> <span class="o">(</span><span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">Nat</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">m.succ</span> <span class="bp">=</span> <span class="n">n.succ</span><span class="o">)</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">=</span> <span class="n">n</span> <span class="o">:=</span> <span class="n">Nat.succ.inj</span> <span class="n">h</span> </pre></div> </div> <p>What the word “inductively” means for the working mathematician is that the natural numbers comes with a principle of proof by induction and a principle of definition by recursion. This section will show you how to use these.</p> <p>Here is an example of a recursive definition of the factorial function.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">fac</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℕ</span> <span class="bp">|</span> <span class="mi">0</span> <span class="bp">=></span> <span class="mi">1</span> <span class="bp">|</span> <span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span> <span class="bp">=></span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="bp">*</span> <span class="n">fac</span> <span class="n">n</span> </pre></div> </div> <p>The syntax takes some getting used to. Notice that there is no <code class="docutils literal notranslate"><span class="pre">:=</span></code> on the first line. The next two lines provide the base case and inductive step for a recursive definition. These equations hold definitionally, but they can also be used manually by giving the name <code class="docutils literal notranslate"><span class="pre">fac</span></code> to <code class="docutils literal notranslate"><span class="pre">simp</span></code> or <code class="docutils literal notranslate"><span class="pre">rw</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">fac</span> <span class="mi">0</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">fac</span> <span class="mi">0</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">fac</span><span class="o">]</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">fac</span> <span class="mi">0</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="o">[</span><span class="n">fac</span><span class="o">]</span> <span class="kd">example</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="n">fac</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="bp">=</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="bp">*</span> <span class="n">fac</span> <span class="n">n</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">example</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="n">fac</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="bp">=</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="bp">*</span> <span class="n">fac</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">fac</span><span class="o">]</span> <span class="kd">example</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="n">fac</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="bp">=</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="bp">*</span> <span class="n">fac</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="o">[</span><span class="n">fac</span><span class="o">]</span> </pre></div> </div> <p>The factorial function is actually already defined in mathlib as <code class="docutils literal notranslate"><span class="pre">Nat.factorial</span></code>. Once again, you can jump to it by typing <code class="docutils literal notranslate"><span class="pre">#check</span> <span class="pre">Nat.factorial</span></code> and using <code class="docutils literal notranslate"><span class="pre">ctrl-click.</span></code> For illustrative purposes, we will continue using <code class="docutils literal notranslate"><span class="pre">fac</span></code> in the examples. The annotation <code class="docutils literal notranslate"><span class="pre">@[simp]</span></code> before the definition of <code class="docutils literal notranslate"><span class="pre">Nat.factorial</span></code> specifies that the defining equation should be added to the database of identities that the simplifier uses by default.</p> <p>The principle of induction says that we can prove a general statement about the natural numbers by proving that the statement holds of 0 and that whenever it holds of a natural number <span class="math notranslate nohighlight">\(n\)</span>, it also holds of <span class="math notranslate nohighlight">\(n + 1\)</span>. The line <code class="docutils literal notranslate"><span class="pre">induction</span> <span class="pre">n</span> <span class="pre">with</span> <span class="pre">n</span> <span class="pre">ih</span></code> in the proof below therefore results in two goals: in the first we need to prove <code class="docutils literal notranslate"><span class="pre">0</span> <span class="pre"><</span> <span class="pre">fac</span> <span class="pre">0</span></code>, and in the second we have the added assumption <code class="docutils literal notranslate"><span class="pre">ih</span> <span class="pre">:</span> <span class="pre">0</span> <span class="pre"><</span> <span class="pre">fac</span> <span class="pre">n</span></code> and a required to prove <code class="docutils literal notranslate"><span class="pre">0</span> <span class="pre"><</span> <span class="pre">fac</span> <span class="pre">(n</span> <span class="pre">+</span> <span class="pre">1)</span></code>. The phrase <code class="docutils literal notranslate"><span class="pre">with</span> <span class="pre">n</span> <span class="pre">ih</span></code> serves to name the variable and the assumption for the inductive hypothesis, and you can choose whatever names you want for them.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">fac_pos</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">fac</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">induction'</span> <span class="n">n</span> <span class="k">with</span> <span class="n">n</span> <span class="n">ih</span> <span class="bp">·</span> <span class="n">rw</span> <span class="o">[</span><span class="n">fac</span><span class="o">]</span> <span class="n">exact</span> <span class="n">zero_lt_one</span> <span class="n">rw</span> <span class="o">[</span><span class="n">fac</span><span class="o">]</span> <span class="n">exact</span> <span class="n">mul_pos</span> <span class="n">n.succ_pos</span> <span class="n">ih</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">induction</span></code> tactic is smart enough to include hypotheses that depend on the induction variable as part of the induction hypothesis. Step through the next example to see what is going on.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">dvd_fac</span> <span class="o">{</span><span class="n">i</span> <span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">ipos</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">i</span><span class="o">)</span> <span class="o">(</span><span class="n">ile</span> <span class="o">:</span> <span class="n">i</span> <span class="bp">≤</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="n">i</span> <span class="bp">∣</span> <span class="n">fac</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">induction'</span> <span class="n">n</span> <span class="k">with</span> <span class="n">n</span> <span class="n">ih</span> <span class="bp">·</span> <span class="n">exact</span> <span class="n">absurd</span> <span class="n">ipos</span> <span class="o">(</span><span class="n">not_lt_of_ge</span> <span class="n">ile</span><span class="o">)</span> <span class="n">rw</span> <span class="o">[</span><span class="n">fac</span><span class="o">]</span> <span class="n">cases'</span> <span class="n">Nat.of_le_succ</span> <span class="n">ile</span> <span class="k">with</span> <span class="n">h</span> <span class="n">h</span> <span class="bp">·</span> <span class="n">apply</span> <span class="n">dvd_mul_of_dvd_right</span> <span class="o">(</span><span class="n">ih</span> <span class="n">h</span><span class="o">)</span> <span class="n">rw</span> <span class="o">[</span><span class="n">h</span><span class="o">]</span> <span class="n">apply</span> <span class="n">dvd_mul_right</span> </pre></div> </div> <p>The following example provides a crude lower bound for the factorial function. It turns out to be easier to start with a proof by cases, so that the remainder of the proof starts with the case <span class="math notranslate nohighlight">\(n = 1\)</span>. See if you can complete the argument with a proof by induction.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">pow_two_le_fac</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">^</span> <span class="o">(</span><span class="n">n</span> <span class="bp">-</span> <span class="mi">1</span><span class="o">)</span> <span class="bp">≤</span> <span class="n">fac</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">cases'</span> <span class="n">n</span> <span class="k">with</span> <span class="n">n</span> <span class="bp">·</span> <span class="n">simp</span> <span class="o">[</span><span class="n">fac</span><span class="o">]</span> <span class="gr">sorry</span> </pre></div> </div> <p>Induction is often used to prove identities involving finite sums and products. Mathlib defines the expressions <code class="docutils literal notranslate"><span class="pre">Finset.sum</span> <span class="pre">s</span> <span class="pre">f</span></code> where <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">:</span> <span class="pre">Finset</span> <span class="pre">α</span></code> if a finite set of elements of the type <code class="docutils literal notranslate"><span class="pre">α</span></code> and <code class="docutils literal notranslate"><span class="pre">f</span></code> is a function defined on <code class="docutils literal notranslate"><span class="pre">α</span></code>. The codomain of <code class="docutils literal notranslate"><span class="pre">f</span></code> can be any type that supports a commutative, associative addition operation with a zero element. If you import <code class="docutils literal notranslate"><span class="pre">Algebra.BigOperators.Basic</span></code> and issue the command <code class="docutils literal notranslate"><span class="pre">open</span> <span class="pre">BigOperators</span></code>, you can use the more suggestive notation <code class="docutils literal notranslate"><span class="pre">∑</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">s,</span> <span class="pre">f</span> <span class="pre">x</span></code>. Of course, there is are an analogous operation and notation for finite products.</p> <p>We will talk about the <code class="docutils literal notranslate"><span class="pre">Finset</span></code> type and the operations it supports in the next section, and again in a later chapter. For now, we will only make use of <code class="docutils literal notranslate"><span class="pre">Finset.range</span> <span class="pre">n</span></code>, which is the finite set of natural numbers less than <code class="docutils literal notranslate"><span class="pre">n</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">(</span><span class="n">s</span> <span class="o">:</span> <span class="n">Finset</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="k">#check</span> <span class="n">Finset.sum</span> <span class="n">s</span> <span class="n">f</span> <span class="k">#check</span> <span class="n">Finset.prod</span> <span class="n">s</span> <span class="n">f</span> <span class="kn">open</span> <span class="n">BigOperators</span> <span class="kn">open</span> <span class="n">Finset</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">s.sum</span> <span class="n">f</span> <span class="bp">=</span> <span class="bp">∑</span> <span class="n">x</span> <span class="k">in</span> <span class="n">s</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">s.prod</span> <span class="n">f</span> <span class="bp">=</span> <span class="bp">∏</span> <span class="n">x</span> <span class="k">in</span> <span class="n">s</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">range</span> <span class="n">n</span><span class="o">)</span><span class="bp">.</span><span class="n">sum</span> <span class="n">f</span> <span class="bp">=</span> <span class="bp">∑</span> <span class="n">x</span> <span class="k">in</span> <span class="n">range</span> <span class="n">n</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">range</span> <span class="n">n</span><span class="o">)</span><span class="bp">.</span><span class="n">prod</span> <span class="n">f</span> <span class="bp">=</span> <span class="bp">∏</span> <span class="n">x</span> <span class="k">in</span> <span class="n">range</span> <span class="n">n</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">rfl</span> </pre></div> </div> <p>The facts <code class="docutils literal notranslate"><span class="pre">Finset.sum_range_zero</span></code> and <code class="docutils literal notranslate"><span class="pre">Finset.sum_range_succ</span></code> provide a recursive description summation up to <span class="math notranslate nohighlight">\(n\)</span>, and similarly for products.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="bp">∑</span> <span class="n">x</span> <span class="k">in</span> <span class="n">range</span> <span class="mi">0</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="n">Finset.sum_range_zero</span> <span class="n">f</span> <span class="kd">example</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="bp">∑</span> <span class="n">x</span> <span class="k">in</span> <span class="n">range</span> <span class="n">n.succ</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="bp">=</span> <span class="o">(</span><span class="bp">∑</span> <span class="n">x</span> <span class="k">in</span> <span class="n">range</span> <span class="n">n</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="bp">+</span> <span class="n">f</span> <span class="n">n</span> <span class="o">:=</span> <span class="n">Finset.sum_range_succ</span> <span class="n">f</span> <span class="n">n</span> <span class="kd">example</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="bp">∏</span> <span class="n">x</span> <span class="k">in</span> <span class="n">range</span> <span class="mi">0</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">:=</span> <span class="n">Finset.prod_range_zero</span> <span class="n">f</span> <span class="kd">example</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="bp">∏</span> <span class="n">x</span> <span class="k">in</span> <span class="n">range</span> <span class="n">n.succ</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="bp">=</span> <span class="o">(</span><span class="bp">∏</span> <span class="n">x</span> <span class="k">in</span> <span class="n">range</span> <span class="n">n</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="bp">*</span> <span class="n">f</span> <span class="n">n</span> <span class="o">:=</span> <span class="n">Finset.prod_range_succ</span> <span class="n">f</span> <span class="n">n</span> </pre></div> </div> <p>The first identity in each pair holds definitionally, which is to say, you can replace the proofs by <code class="docutils literal notranslate"><span class="pre">rfl</span></code>.</p> <p>The following expresses the factorial function that we defined as a product.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="n">fac</span> <span class="n">n</span> <span class="bp">=</span> <span class="bp">∏</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span> <span class="n">n</span><span class="o">,</span> <span class="o">(</span><span class="n">i</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">induction'</span> <span class="n">n</span> <span class="k">with</span> <span class="n">n</span> <span class="n">ih</span> <span class="bp">·</span> <span class="n">rw</span> <span class="o">[</span><span class="n">fac</span><span class="o">,</span> <span class="n">prod_range_zero</span><span class="o">]</span> <span class="n">rw</span> <span class="o">[</span><span class="n">fac</span><span class="o">,</span> <span class="n">ih</span><span class="o">,</span> <span class="n">prod_range_succ</span><span class="o">,</span> <span class="n">mul_comm</span><span class="o">]</span> </pre></div> </div> <p>The fact that we include <code class="docutils literal notranslate"><span class="pre">mul_comm</span></code> as a simplification rule deserves comment. It should seem dangerous to simplify with the identity <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">*</span> <span class="pre">y</span> <span class="pre">=</span> <span class="pre">y</span> <span class="pre">*</span> <span class="pre">x</span></code>, which would ordinarily loop indefinitely. Lean’s simplifier is smart enough to recognize that, and applies the rule only in the case where the resulting term has a smaller value in some fixed but arbitrary ordering of the terms. The following example shows that simplifying using the three rules <code class="docutils literal notranslate"><span class="pre">mul_assoc</span></code>, <code class="docutils literal notranslate"><span class="pre">mul_comm</span></code>, and <code class="docutils literal notranslate"><span class="pre">mul_left_comm</span></code> manages to identify products that are the same up to the placement of parentheses and ordering of variables.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="n">d</span> <span class="n">e</span> <span class="n">f</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="o">(</span><span class="n">b</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">*</span> <span class="n">f</span> <span class="bp">*</span> <span class="o">(</span><span class="n">d</span> <span class="bp">*</span> <span class="n">e</span><span class="o">))</span> <span class="bp">=</span> <span class="n">d</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">f</span> <span class="bp">*</span> <span class="n">e</span><span class="o">)</span> <span class="bp">*</span> <span class="o">(</span><span class="n">c</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="o">[</span><span class="n">mul_assoc</span><span class="o">,</span> <span class="n">mul_comm</span><span class="o">,</span> <span class="n">mul_left_comm</span><span class="o">]</span> </pre></div> </div> <p>Roughly, the rules work by pushing parentheses to the right and then re-ordering the expressions on both sides until they both follow the same canonical order. Simplifying with these rules, and the corresponding rules for addition, is a handy trick.</p> <p>Returning to summation identities, we suggest stepping through the following proof that the sum of the natural numbers up to an including <span class="math notranslate nohighlight">\(n\)</span> is <span class="math notranslate nohighlight">\(n (n + 1) / 2\)</span>. The first step of the proof clears the denominator. This is generally useful when formalizing identities, because calculations with division generally have side conditions. (It is similarly useful to avoid using subtraction on the natural numbers when possible.)</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">sum_id</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="bp">∑</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">),</span> <span class="n">i</span><span class="o">)</span> <span class="bp">=</span> <span class="n">n</span> <span class="bp">*</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="bp">/</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">symm</span><span class="bp">;</span> <span class="n">apply</span> <span class="n">Nat.div_eq_of_eq_mul_right</span> <span class="o">(</span><span class="kd">by</span> <span class="n">norm_num</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="mi">2</span><span class="o">)</span> <span class="n">induction'</span> <span class="n">n</span> <span class="k">with</span> <span class="n">n</span> <span class="n">ih</span> <span class="bp">·</span> <span class="n">simp</span> <span class="n">rw</span> <span class="o">[</span><span class="n">Finset.sum_range_succ</span><span class="o">,</span> <span class="n">mul_add</span> <span class="mi">2</span><span class="o">,</span> <span class="bp">←</span> <span class="n">ih</span><span class="o">,</span> <span class="n">Nat.succ_eq_add_one</span><span class="o">]</span> <span class="n">ring</span> </pre></div> </div> <p>We encourage you to prove the analogous identity for sums of squares, and other identities you can find on the web.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">sum_sqr</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="bp">∑</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">),</span> <span class="n">i</span> <span class="bp">^</span> <span class="mi">2</span><span class="o">)</span> <span class="bp">=</span> <span class="n">n</span> <span class="bp">*</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="bp">*</span> <span class="o">(</span><span class="mi">2</span> <span class="bp">*</span> <span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="bp">/</span> <span class="mi">6</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>In Lean’s core library, addition and multiplication are themselves defined using recursive definitions, and their fundamental properties are established using induction. If you like thinking about foundational topics like that, you might enjoy working through proofs of the commutativity and associativity of multiplication and addition and the distributivity of multiplication over addition. You can do this on a copy of the natural numbers following the outline below. Notice that we can use the <code class="docutils literal notranslate"><span class="pre">induction</span></code> tactic with <code class="docutils literal notranslate"><span class="pre">MyNat</span></code>; Lean is smart enough to know to use the relevant induction principle (which is, of course, the same as that for <code class="docutils literal notranslate"><span class="pre">Nat</span></code>).</p> <p>We start you off with the commutativity of addition. A good rule of thumb is that because addition and multiplication are defined by recursion on the second argument, it is generally advantageous to do proofs by induction on a variable that occurs in that position. It is a bit tricky to decide which variable to use in the proof of associativity.</p> <p>It can be confusing to write things without the usual notation for zero, one, addition, and multiplication. We will learn how to define such notation later. Working in the namespace <code class="docutils literal notranslate"><span class="pre">MyNat</span></code> means that we can write <code class="docutils literal notranslate"><span class="pre">zero</span></code> and <code class="docutils literal notranslate"><span class="pre">succ</span></code> rather than <code class="docutils literal notranslate"><span class="pre">MyNat.zero</span></code> and <code class="docutils literal notranslate"><span class="pre">MyNat.succ</span></code>, and that these interpretations of the names take precedence over others. Outside the namespace, the full name of the <code class="docutils literal notranslate"><span class="pre">add</span></code> defined below, for example, is <code class="docutils literal notranslate"><span class="pre">MyNat.add</span></code>.</p> <p>If you find that you <em>really</em> enjoy this sort of thing, try defining truncated subtraction and exponentiation and proving some of their properties as well. Remember that truncated subtraction cuts off at zero. To define that, it is useful to define a predecessor function, <code class="docutils literal notranslate"><span class="pre">pred</span></code>, that subtracts one from any nonzero number and fixes zero. The function <code class="docutils literal notranslate"><span class="pre">pred</span></code> can be defined by a simple instance of recursion.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">inductive</span> <span class="n">MyNat</span> <span class="bp">|</span> <span class="n">zero</span> <span class="o">:</span> <span class="n">MyNat</span> <span class="bp">|</span> <span class="n">succ</span> <span class="o">:</span> <span class="n">MyNat</span> <span class="bp">→</span> <span class="n">MyNat</span> <span class="kn">namespace</span> <span class="n">MyNat</span> <span class="kd">def</span> <span class="n">add</span> <span class="o">:</span> <span class="n">MyNat</span> <span class="bp">→</span> <span class="n">MyNat</span> <span class="bp">→</span> <span class="n">MyNat</span> <span class="bp">|</span> <span class="n">x</span><span class="o">,</span> <span class="n">zero</span> <span class="bp">=></span> <span class="n">x</span> <span class="bp">|</span> <span class="n">x</span><span class="o">,</span> <span class="n">succ</span> <span class="n">y</span> <span class="bp">=></span> <span class="n">succ</span> <span class="o">(</span><span class="n">add</span> <span class="n">x</span> <span class="n">y</span><span class="o">)</span> <span class="kd">def</span> <span class="n">mul</span> <span class="o">:</span> <span class="n">MyNat</span> <span class="bp">→</span> <span class="n">MyNat</span> <span class="bp">→</span> <span class="n">MyNat</span> <span class="bp">|</span> <span class="n">x</span><span class="o">,</span> <span class="n">zero</span> <span class="bp">=></span> <span class="n">zero</span> <span class="bp">|</span> <span class="n">x</span><span class="o">,</span> <span class="n">succ</span> <span class="n">y</span> <span class="bp">=></span> <span class="n">add</span> <span class="o">(</span><span class="n">mul</span> <span class="n">x</span> <span class="n">y</span><span class="o">)</span> <span class="n">x</span> <span class="kd">theorem</span> <span class="n">zero_add</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">MyNat</span><span class="o">)</span> <span class="o">:</span> <span class="n">add</span> <span class="n">zero</span> <span class="n">n</span> <span class="bp">=</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">induction'</span> <span class="n">n</span> <span class="k">with</span> <span class="n">n</span> <span class="n">ih</span> <span class="bp">·</span> <span class="n">rfl</span> <span class="n">rw</span> <span class="o">[</span><span class="n">add</span><span class="o">,</span> <span class="n">ih</span><span class="o">]</span> <span class="kd">theorem</span> <span class="n">succ_add</span> <span class="o">(</span><span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">MyNat</span><span class="o">)</span> <span class="o">:</span> <span class="n">add</span> <span class="o">(</span><span class="n">succ</span> <span class="n">m</span><span class="o">)</span> <span class="n">n</span> <span class="bp">=</span> <span class="n">succ</span> <span class="o">(</span><span class="n">add</span> <span class="n">m</span> <span class="n">n</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">induction'</span> <span class="n">n</span> <span class="k">with</span> <span class="n">n</span> <span class="n">ih</span> <span class="bp">·</span> <span class="n">rfl</span> <span class="n">rw</span> <span class="o">[</span><span class="n">add</span><span class="o">,</span> <span class="n">ih</span><span class="o">]</span> <span class="n">rfl</span> <span class="kd">theorem</span> <span class="n">add_comm</span> <span class="o">(</span><span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">MyNat</span><span class="o">)</span> <span class="o">:</span> <span class="n">add</span> <span class="n">m</span> <span class="n">n</span> <span class="bp">=</span> <span class="n">add</span> <span class="n">n</span> <span class="n">m</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">induction'</span> <span class="n">n</span> <span class="k">with</span> <span class="n">n</span> <span class="n">ih</span> <span class="bp">·</span> <span class="n">rw</span> <span class="o">[</span><span class="n">zero_add</span><span class="o">]</span> <span class="n">rfl</span> <span class="n">rw</span> <span class="o">[</span><span class="n">add</span><span class="o">,</span> <span class="n">succ_add</span><span class="o">,</span> <span class="n">ih</span><span class="o">]</span> <span class="kd">theorem</span> <span class="n">add_assoc</span> <span class="o">(</span><span class="n">m</span> <span class="n">n</span> <span class="n">k</span> <span class="o">:</span> <span class="n">MyNat</span><span class="o">)</span> <span class="o">:</span> <span class="n">add</span> <span class="o">(</span><span class="n">add</span> <span class="n">m</span> <span class="n">n</span><span class="o">)</span> <span class="n">k</span> <span class="bp">=</span> <span class="n">add</span> <span class="n">m</span> <span class="o">(</span><span class="n">add</span> <span class="n">n</span> <span class="n">k</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">mul_add</span> <span class="o">(</span><span class="n">m</span> <span class="n">n</span> <span class="n">k</span> <span class="o">:</span> <span class="n">MyNat</span><span class="o">)</span> <span class="o">:</span> <span class="n">mul</span> <span class="n">m</span> <span class="o">(</span><span class="n">add</span> <span class="n">n</span> <span class="n">k</span><span class="o">)</span> <span class="bp">=</span> <span class="n">add</span> <span class="o">(</span><span class="n">mul</span> <span class="n">m</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">mul</span> <span class="n">m</span> <span class="n">k</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">zero_mul</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">MyNat</span><span class="o">)</span> <span class="o">:</span> <span class="n">mul</span> <span class="n">zero</span> <span class="n">n</span> <span class="bp">=</span> <span class="n">zero</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">succ_mul</span> <span class="o">(</span><span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">MyNat</span><span class="o">)</span> <span class="o">:</span> <span class="n">mul</span> <span class="o">(</span><span class="n">succ</span> <span class="n">m</span><span class="o">)</span> <span class="n">n</span> <span class="bp">=</span> <span class="n">add</span> <span class="o">(</span><span class="n">mul</span> <span class="n">m</span> <span class="n">n</span><span class="o">)</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">mul_comm</span> <span class="o">(</span><span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">MyNat</span><span class="o">)</span> <span class="o">:</span> <span class="n">mul</span> <span class="n">m</span> <span class="n">n</span> <span class="bp">=</span> <span class="n">mul</span> <span class="n">n</span> <span class="n">m</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">end</span> <span class="n">MyNat</span> </pre></div> </div> </section> <section id="infinitely-many-primes"> <span id="section-infinitely-many-primes"></span><h2><span class="section-number">5.3. </span>Infinitely Many Primes<a class="headerlink" href="#infinitely-many-primes" title="Permalink to this heading"></a></h2> <p>Let us continue our exploration of induction and recursion with another mathematical standard: a proof that there are infinitely many primes. One way to formulate this is as the statement that for every natural number <span class="math notranslate nohighlight">\(n\)</span>, there is a prime number greater than <span class="math notranslate nohighlight">\(n\)</span>. To prove this, let <span class="math notranslate nohighlight">\(p\)</span> be any prime factor of <span class="math notranslate nohighlight">\(n! + 1\)</span>. If <span class="math notranslate nohighlight">\(p\)</span> is less than <span class="math notranslate nohighlight">\(n\)</span>, it divides <span class="math notranslate nohighlight">\(n!\)</span>. Since it also divides <span class="math notranslate nohighlight">\(n! + 1\)</span>, it divides 1, a contradiction. Hence <span class="math notranslate nohighlight">\(p\)</span> is greater than <span class="math notranslate nohighlight">\(n\)</span>.</p> <p>To formalize that proof, we need to show that any number greater than or equal to 2 has a prime factor. To do that, we will need to show that any natural number that is not equal to 0 or 1 is greater-than or equal to 2. And this brings us to a quirky feature of formalization: it is often trivial statements like this that are among the most annoying to formalize. Here we consider a few ways to do it.</p> <p>To start with, we can use the <code class="docutils literal notranslate"><span class="pre">cases</span></code> tactic and the fact that the successor function respects the ordering on the natural numbers.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">two_le</span> <span class="o">{</span><span class="n">m</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">h0</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">≠</span> <span class="mi">0</span><span class="o">)</span> <span class="o">(</span><span class="n">h1</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">≠</span> <span class="mi">1</span><span class="o">)</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">≤</span> <span class="n">m</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">cases</span> <span class="n">m</span><span class="bp">;</span> <span class="n">contradiction</span> <span class="n">case</span> <span class="n">succ</span> <span class="n">m</span> <span class="bp">=></span> <span class="n">cases</span> <span class="n">m</span><span class="bp">;</span> <span class="n">contradiction</span> <span class="n">repeat'</span> <span class="n">apply</span> <span class="n">Nat.succ_le_succ</span> <span class="n">apply</span> <span class="n">zero_le</span> </pre></div> </div> <p>Another strategy is to use the tactic <code class="docutils literal notranslate"><span class="pre">interval_cases</span></code>, which automatically splits the goal into cases when the variable in question is contained in an interval of natural numbers or integers. Remember that you can hover over it to see its documentation.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">m</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">h0</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">≠</span> <span class="mi">0</span><span class="o">)</span> <span class="o">(</span><span class="n">h1</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">≠</span> <span class="mi">1</span><span class="o">)</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">≤</span> <span class="n">m</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">by_contra</span> <span class="n">h</span> <span class="n">push_neg</span> <span class="n">at</span> <span class="n">h</span> <span class="n">interval_cases</span> <span class="n">m</span> <span class="bp"><;></span> <span class="n">contradiction</span> </pre></div> </div> <p>Recall that the semicolon after <code class="docutils literal notranslate"><span class="pre">interval_cases</span> <span class="pre">m</span></code> means that the next tactic is applied to each of the cases that it generates. Yet another option is to use the tactic, <code class="docutils literal notranslate"><span class="pre">decide</span></code>, which tries to find a decision procedure to solve the problem. Lean knows that you can decide the truth value of a statement that begins with a bounded quantifier <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">x,</span> <span class="pre">x</span> <span class="pre"><</span> <span class="pre">n</span> <span class="pre">→</span> <span class="pre">...</span></code> or <code class="docutils literal notranslate"><span class="pre">∃</span> <span class="pre">x,</span> <span class="pre">x</span> <span class="pre"><</span> <span class="pre">n</span> <span class="pre">∧</span> <span class="pre">...</span></code> by deciding each of the finitely many instances.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">m</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">h0</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">≠</span> <span class="mi">0</span><span class="o">)</span> <span class="o">(</span><span class="n">h1</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">≠</span> <span class="mi">1</span><span class="o">)</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">≤</span> <span class="n">m</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">by_contra</span> <span class="n">h</span> <span class="n">push_neg</span> <span class="n">at</span> <span class="n">h</span> <span class="n">revert</span> <span class="n">h0</span> <span class="n">h1</span> <span class="n">revert</span> <span class="n">h</span> <span class="n">m</span> <span class="n">decide</span> </pre></div> </div> <p>With the theorem <code class="docutils literal notranslate"><span class="pre">two_le</span></code> in hand, let’s start by showing that every natural number greater than two has a prime divisor. Mathlib contains a function <code class="docutils literal notranslate"><span class="pre">Nat.minFac</span></code> that returns the smallest prime divisor, but for the sake of learning new parts of the library, we’ll avoid using it and prove the theorem directly.</p> <p>Here, ordinary induction isn’t enough. We want to use <em>strong induction</em>, which allows us to prove that every natural number <span class="math notranslate nohighlight">\(n\)</span> has a property <span class="math notranslate nohighlight">\(P\)</span> by showing that for every number <span class="math notranslate nohighlight">\(n\)</span>, if <span class="math notranslate nohighlight">\(P\)</span> holds of all values less than <span class="math notranslate nohighlight">\(n\)</span>, it holds at <span class="math notranslate nohighlight">\(n\)</span> as well. In Lean, this principle is called <code class="docutils literal notranslate"><span class="pre">Nat.strong_induction_on</span></code>, and we can use the <code class="docutils literal notranslate"><span class="pre">with</span></code> keyword to tell the induction tactic to use it. Notice that when we do that, there is no base case; it is subsumed by the general induction step.</p> <p>The argument is simply as follows. Assuming <span class="math notranslate nohighlight">\(n ≥ 2\)</span>, if <span class="math notranslate nohighlight">\(n\)</span> is prime, we’re done. If it isn’t, then by one of the characterizations of what it means to be a prime number, it has a nontrivial factor, <span class="math notranslate nohighlight">\(m\)</span>, and we can apply the inductive hypothesis to that. Step through the next proof to see how that plays out. The line <code class="docutils literal notranslate"><span class="pre">dsimp</span> <span class="pre">at</span> <span class="pre">ih</span></code> simplifies the expression of the inductive hypothesis to make it more readable. The proof still works if you delete that line.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">exists_prime_factor</span> <span class="o">{</span><span class="n">n</span> <span class="o">:</span> <span class="n">Nat</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">≤</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">p</span> <span class="o">:</span> <span class="n">Nat</span><span class="o">,</span> <span class="n">p.Prime</span> <span class="bp">∧</span> <span class="n">p</span> <span class="bp">∣</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">by_cases</span> <span class="n">np</span> <span class="o">:</span> <span class="n">n.Prime</span> <span class="bp">·</span> <span class="n">use</span> <span class="n">n</span><span class="o">,</span> <span class="n">np</span> <span class="n">induction'</span> <span class="n">n</span> <span class="n">using</span> <span class="n">Nat.strong_induction_on</span> <span class="k">with</span> <span class="n">n</span> <span class="n">ih</span> <span class="n">dsimp</span> <span class="n">at</span> <span class="n">ih</span> <span class="n">rw</span> <span class="o">[</span><span class="n">Nat.prime_def_lt</span><span class="o">]</span> <span class="n">at</span> <span class="n">np</span> <span class="n">push_neg</span> <span class="n">at</span> <span class="n">np</span> <span class="n">rcases</span> <span class="n">np</span> <span class="n">h</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">m</span><span class="o">,</span> <span class="n">mltn</span><span class="o">,</span> <span class="n">mdvdn</span><span class="o">,</span> <span class="n">mne1</span><span class="o">⟩</span> <span class="k">have</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">≠</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">mz</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mz</span><span class="o">,</span> <span class="n">zero_dvd_iff</span><span class="o">]</span> <span class="n">at</span> <span class="n">mdvdn</span> <span class="n">linarith</span> <span class="k">have</span> <span class="n">mgt2</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">≤</span> <span class="n">m</span> <span class="o">:=</span> <span class="n">two_le</span> <span class="n">this</span> <span class="n">mne1</span> <span class="n">by_cases</span> <span class="n">mp</span> <span class="o">:</span> <span class="n">m.Prime</span> <span class="bp">·</span> <span class="n">use</span> <span class="n">m</span><span class="o">,</span> <span class="n">mp</span> <span class="n">exact</span> <span class="n">mdvdn</span> <span class="bp">.</span> <span class="n">rcases</span> <span class="n">ih</span> <span class="n">m</span> <span class="n">mltn</span> <span class="n">mgt2</span> <span class="n">mp</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">p</span><span class="o">,</span> <span class="n">pp</span><span class="o">,</span> <span class="n">pdvd</span><span class="o">⟩</span> <span class="n">use</span> <span class="n">p</span><span class="o">,</span> <span class="n">pp</span> <span class="n">apply</span> <span class="n">pdvd.trans</span> <span class="n">mdvdn</span> </pre></div> </div> <p>We can now prove the following formulation of our theorem. See if you can fill out the sketch. You can use <code class="docutils literal notranslate"><span class="pre">Nat.factorial_pos</span></code>, <code class="docutils literal notranslate"><span class="pre">Nat.dvd_factorial</span></code>, and <code class="docutils literal notranslate"><span class="pre">Nat.dvd_sub</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">primes_infinite</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">p</span> <span class="bp">></span> <span class="n">n</span><span class="o">,</span> <span class="n">Nat.Prime</span> <span class="n">p</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">n</span> <span class="k">have</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">≤</span> <span class="n">Nat.factorial</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="bp">+</span> <span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="n">rcases</span> <span class="n">exists_prime_factor</span> <span class="n">this</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">p</span><span class="o">,</span> <span class="n">pp</span><span class="o">,</span> <span class="n">pdvd</span><span class="o">⟩</span> <span class="n">refine'</span> <span class="o">⟨</span><span class="n">p</span><span class="o">,</span> <span class="n">_</span><span class="o">,</span> <span class="n">pp</span><span class="o">⟩</span> <span class="k">show</span> <span class="n">p</span> <span class="bp">></span> <span class="n">n</span> <span class="n">by_contra</span> <span class="n">ple</span> <span class="n">push_neg</span> <span class="n">at</span> <span class="n">ple</span> <span class="k">have</span> <span class="o">:</span> <span class="n">p</span> <span class="bp">∣</span> <span class="n">Nat.factorial</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="o">:</span> <span class="n">p</span> <span class="bp">∣</span> <span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">show</span> <span class="n">False</span> <span class="gr">sorry</span> </pre></div> </div> <p>Let’s consider a variation of the proof above, where instead of using the factorial function, we suppose that we are given by a finite set <span class="math notranslate nohighlight">\(\{ p_1, \ldots, p_n \}\)</span> and we consider a prime factor of <span class="math notranslate nohighlight">\(\prod_{i = 1}^n p_i + 1\)</span>. That prime factor has to be distinct from each <span class="math notranslate nohighlight">\(p_i\)</span>, showing that there is no finite set that contains all the prime numbers.</p> <p>Formalizing this argument requires us to reason about finite sets. In Lean, for any type <code class="docutils literal notranslate"><span class="pre">α</span></code>, the type <code class="docutils literal notranslate"><span class="pre">Finset</span> <span class="pre">α</span></code> represents finite sets of elements of type <code class="docutils literal notranslate"><span class="pre">α</span></code>. Reasoning about finite sets computationally requires having a procedure to test equality on <code class="docutils literal notranslate"><span class="pre">α</span></code>, which is why the snippet below includes the assumption <code class="docutils literal notranslate"><span class="pre">[DecidableEq</span> <span class="pre">α]</span></code>. For concrete data types like <code class="docutils literal notranslate"><span class="pre">ℕ</span></code>, <code class="docutils literal notranslate"><span class="pre">ℤ</span></code>, and <code class="docutils literal notranslate"><span class="pre">ℚ</span></code>, the assumption is satisfied automatically. When reasoning about the real numbers, it can be satisfied using classical logic and abandoning the computational interpretation.</p> <p>We use the command <code class="docutils literal notranslate"><span class="pre">open</span> <span class="pre">Finset</span></code> to avail ourselves of shorter names for the relevant theorems. Unlike the case with sets, most equivalences involving finsets do not hold definitionally, so they need to be expanded manually using equivalances like <code class="docutils literal notranslate"><span class="pre">Finset.subset_iff</span></code>, <code class="docutils literal notranslate"><span class="pre">Finset.mem_union</span></code>, <code class="docutils literal notranslate"><span class="pre">Finset.mem_inter</span></code>, and <code class="docutils literal notranslate"><span class="pre">Finset.mem_sdiff</span></code>. The <code class="docutils literal notranslate"><span class="pre">ext</span></code> tactic can still be used to reduce show that two finite sets are equal by showing that every element of one is an element of the other.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">open</span> <span class="n">Finset</span> <span class="kn">section</span> <span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">DecidableEq</span> <span class="n">α</span><span class="o">]</span> <span class="o">(</span><span class="n">r</span> <span class="n">s</span> <span class="n">t</span> <span class="o">:</span> <span class="n">Finset</span> <span class="n">α</span><span class="o">)</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">r</span> <span class="bp">∩</span> <span class="o">(</span><span class="n">s</span> <span class="bp">∪</span> <span class="n">t</span><span class="o">)</span> <span class="bp">⊆</span> <span class="n">r</span> <span class="bp">∩</span> <span class="n">s</span> <span class="bp">∪</span> <span class="n">r</span> <span class="bp">∩</span> <span class="n">t</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">subset_iff</span><span class="o">]</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mem_inter</span><span class="o">,</span> <span class="n">mem_union</span><span class="o">,</span> <span class="n">mem_union</span><span class="o">,</span> <span class="n">mem_inter</span><span class="o">,</span> <span class="n">mem_inter</span><span class="o">]</span> <span class="n">tauto</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">r</span> <span class="bp">∩</span> <span class="o">(</span><span class="n">s</span> <span class="bp">∪</span> <span class="n">t</span><span class="o">)</span> <span class="bp">⊆</span> <span class="n">r</span> <span class="bp">∩</span> <span class="n">s</span> <span class="bp">∪</span> <span class="n">r</span> <span class="bp">∩</span> <span class="n">t</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="o">[</span><span class="n">subset_iff</span><span class="o">]</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">tauto</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">r</span> <span class="bp">∩</span> <span class="n">s</span> <span class="bp">∪</span> <span class="n">r</span> <span class="bp">∩</span> <span class="n">t</span> <span class="bp">⊆</span> <span class="n">r</span> <span class="bp">∩</span> <span class="o">(</span><span class="n">s</span> <span class="bp">∪</span> <span class="n">t</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="o">[</span><span class="n">subset_iff</span><span class="o">]</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">tauto</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">r</span> <span class="bp">∩</span> <span class="n">s</span> <span class="bp">∪</span> <span class="n">r</span> <span class="bp">∩</span> <span class="n">t</span> <span class="bp">=</span> <span class="n">r</span> <span class="bp">∩</span> <span class="o">(</span><span class="n">s</span> <span class="bp">∪</span> <span class="n">t</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ext</span> <span class="n">x</span> <span class="n">simp</span> <span class="n">tauto</span> <span class="kd">end</span> </pre></div> </div> <p>We have used a new trick: the <code class="docutils literal notranslate"><span class="pre">tauto</span></code> tactic (and a strengthened version, <code class="docutils literal notranslate"><span class="pre">tauto!</span></code>, which uses classical logic) can be used to dispense with propositional tautologies. See if you can use these methods to prove the two examples below.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">r</span> <span class="bp">∪</span> <span class="n">s</span><span class="o">)</span> <span class="bp">∩</span> <span class="o">(</span><span class="n">r</span> <span class="bp">∪</span> <span class="n">t</span><span class="o">)</span> <span class="bp">=</span> <span class="n">r</span> <span class="bp">∪</span> <span class="n">s</span> <span class="bp">∩</span> <span class="n">t</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">r</span> <span class="bp">\</span> <span class="n">s</span><span class="o">)</span> <span class="bp">\</span> <span class="n">t</span> <span class="bp">=</span> <span class="n">r</span> <span class="bp">\</span> <span class="o">(</span><span class="n">s</span> <span class="bp">∪</span> <span class="n">t</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>The theorem <code class="docutils literal notranslate"><span class="pre">Finset.dvd_prod_of_mem</span></code> tells us that if an <code class="docutils literal notranslate"><span class="pre">n</span></code> is an element of a finite set <code class="docutils literal notranslate"><span class="pre">s</span></code>, then <code class="docutils literal notranslate"><span class="pre">n</span></code> divides <code class="docutils literal notranslate"><span class="pre">∏</span> <span class="pre">i</span> <span class="pre">in</span> <span class="pre">s,</span> <span class="pre">i</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">s</span> <span class="o">:</span> <span class="n">Finset</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">n</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">)</span> <span class="o">:</span> <span class="n">n</span> <span class="bp">∣</span> <span class="bp">∏</span> <span class="n">i</span> <span class="k">in</span> <span class="n">s</span><span class="o">,</span> <span class="n">i</span> <span class="o">:=</span> <span class="n">Finset.dvd_prod_of_mem</span> <span class="n">_</span> <span class="n">h</span> </pre></div> </div> <p>We also need to know that the converse holds in the case where <code class="docutils literal notranslate"><span class="pre">n</span></code> is prime and <code class="docutils literal notranslate"><span class="pre">s</span></code> is a set of primes. To show that, we need the following lemma, which you should be able to prove using the theorem <code class="docutils literal notranslate"><span class="pre">Nat.Prime.eq_one_or_self_of_dvd</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">_root_.Nat.Prime.eq_of_dvd_of_prime</span> <span class="o">{</span><span class="n">p</span> <span class="n">q</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">prime_p</span> <span class="o">:</span> <span class="n">Nat.Prime</span> <span class="n">p</span><span class="o">)</span> <span class="o">(</span><span class="n">prime_q</span> <span class="o">:</span> <span class="n">Nat.Prime</span> <span class="n">q</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">p</span> <span class="bp">∣</span> <span class="n">q</span><span class="o">)</span> <span class="o">:</span> <span class="n">p</span> <span class="bp">=</span> <span class="n">q</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>We can use this lemma to show that if a prime <code class="docutils literal notranslate"><span class="pre">p</span></code> divides a product of a finite set of primes, then it divides one of them. Mathlib provides a useful principle of induction on finite sets: to show that a property holds of an arbitrary finite set <code class="docutils literal notranslate"><span class="pre">s</span></code>, show that it holds of the empty set, and show that it is preserved when we add a single new element <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">∉</span> <span class="pre">s</span></code>. The principle is known as <code class="docutils literal notranslate"><span class="pre">Finset.induction_on</span></code>. When we tell the induction tactic to use it, we can also specify the names <code class="docutils literal notranslate"><span class="pre">a</span></code> and <code class="docutils literal notranslate"><span class="pre">s</span></code>, the name for the assumption <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">∉</span> <span class="pre">s</span></code> in the inductive step, and the name of the inductive hypothesis. The expression <code class="docutils literal notranslate"><span class="pre">Finset.insert</span> <span class="pre">a</span> <span class="pre">s</span></code> denotes the union of <code class="docutils literal notranslate"><span class="pre">s</span></code> with the singleton <code class="docutils literal notranslate"><span class="pre">a</span></code>. The identities <code class="docutils literal notranslate"><span class="pre">Finset.prod_empty</span></code> and <code class="docutils literal notranslate"><span class="pre">Finset.prod_insert</span></code> then provide the relevant rewrite rules for the product. In the proof below, the first <code class="docutils literal notranslate"><span class="pre">simp</span></code> applies <code class="docutils literal notranslate"><span class="pre">Finset.prod_empty</span></code>. Step through the beginning of the proof to see the induction unfold, and then finish it off.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">mem_of_dvd_prod_primes</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Finset</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">{</span><span class="n">p</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">prime_p</span> <span class="o">:</span> <span class="n">p.Prime</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="bp">∀</span> <span class="n">n</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="n">Nat.Prime</span> <span class="n">n</span><span class="o">)</span> <span class="bp">→</span> <span class="o">(</span><span class="n">p</span> <span class="bp">∣</span> <span class="bp">∏</span> <span class="n">n</span> <span class="k">in</span> <span class="n">s</span><span class="o">,</span> <span class="n">n</span><span class="o">)</span> <span class="bp">→</span> <span class="n">p</span> <span class="bp">∈</span> <span class="n">s</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">h₀</span> <span class="n">h₁</span> <span class="n">induction'</span> <span class="n">s</span> <span class="n">using</span> <span class="n">Finset.induction_on</span> <span class="k">with</span> <span class="n">a</span> <span class="n">s</span> <span class="n">ans</span> <span class="n">ih</span> <span class="bp">·</span> <span class="n">simp</span> <span class="n">at</span> <span class="n">h₁</span> <span class="n">linarith</span> <span class="o">[</span><span class="n">prime_p.two_le</span><span class="o">]</span> <span class="n">simp</span> <span class="o">[</span><span class="n">Finset.prod_insert</span> <span class="n">ans</span><span class="o">,</span> <span class="n">prime_p.dvd_mul</span><span class="o">]</span> <span class="n">at</span> <span class="n">h₀</span> <span class="n">h₁</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mem_insert</span><span class="o">]</span> <span class="gr">sorry</span> </pre></div> </div> <p>We need one last property of finite sets. Given an element <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">:</span> <span class="pre">Set</span> <span class="pre">α</span></code> and a predicate <code class="docutils literal notranslate"><span class="pre">P</span></code> on <code class="docutils literal notranslate"><span class="pre">α</span></code>, in <a class="reference internal" href="C04_Sets_and_Functions.html#sets-and-functions"><span class="std std-numref">Chapter 4</span></a> we wrote <code class="docutils literal notranslate"><span class="pre">{</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">s</span> <span class="pre">|</span> <span class="pre">P</span> <span class="pre">x</span> <span class="pre">}</span></code> for the set of elements of <code class="docutils literal notranslate"><span class="pre">s</span></code> that satisfy <code class="docutils literal notranslate"><span class="pre">P</span></code>. Given <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">:</span> <span class="pre">Finset</span> <span class="pre">α</span></code>, the analogous notion is written <code class="docutils literal notranslate"><span class="pre">s.filter</span> <span class="pre">P</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">s</span> <span class="o">:</span> <span class="n">Finset</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s.filter</span> <span class="n">Nat.Prime</span> <span class="bp">↔</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s</span> <span class="bp">∧</span> <span class="n">x.Prime</span> <span class="o">:=</span> <span class="n">mem_filter</span> </pre></div> </div> <p>We now prove an alternative formulation of the statement that there are infinitely many primes, namely, that given any <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">:</span> <span class="pre">Finset</span> <span class="pre">ℕ</span></code>, there is a prime <code class="docutils literal notranslate"><span class="pre">p</span></code> that is not an element of <code class="docutils literal notranslate"><span class="pre">s</span></code>. Aiming for a contradiction, we assume that all the primes are in <code class="docutils literal notranslate"><span class="pre">s</span></code>, and then cut down to a set <code class="docutils literal notranslate"><span class="pre">s'</span></code> that contains all and only the primes. Taking the product of that set, adding one, and finding a prime factor of the result leads to the contradiction we are looking for. See if you can complete the sketch below. You can use <code class="docutils literal notranslate"><span class="pre">Finset.prod_pos</span></code> in the proof of the first <code class="docutils literal notranslate"><span class="pre">have</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">primes_infinite'</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">s</span> <span class="o">:</span> <span class="n">Finset</span> <span class="n">Nat</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">p</span><span class="o">,</span> <span class="n">Nat.Prime</span> <span class="n">p</span> <span class="bp">∧</span> <span class="n">p</span> <span class="bp">∉</span> <span class="n">s</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">s</span> <span class="n">by_contra</span> <span class="n">h</span> <span class="n">push_neg</span> <span class="n">at</span> <span class="n">h</span> <span class="n">set</span> <span class="n">s'</span> <span class="o">:=</span> <span class="n">s.filter</span> <span class="n">Nat.Prime</span> <span class="k">with</span> <span class="n">s'_def</span> <span class="k">have</span> <span class="n">mem_s'</span> <span class="o">:</span> <span class="bp">∀</span> <span class="o">{</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">},</span> <span class="n">n</span> <span class="bp">∈</span> <span class="n">s'</span> <span class="bp">↔</span> <span class="n">n.Prime</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">n</span> <span class="n">simp</span> <span class="o">[</span><span class="n">s'_def</span><span class="o">]</span> <span class="n">apply</span> <span class="n">h</span> <span class="k">have</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">≤</span> <span class="o">(</span><span class="bp">∏</span> <span class="n">i</span> <span class="k">in</span> <span class="n">s'</span><span class="o">,</span> <span class="n">i</span><span class="o">)</span> <span class="bp">+</span> <span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="n">rcases</span> <span class="n">exists_prime_factor</span> <span class="n">this</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">p</span><span class="o">,</span> <span class="n">pp</span><span class="o">,</span> <span class="n">pdvd</span><span class="o">⟩</span> <span class="k">have</span> <span class="o">:</span> <span class="n">p</span> <span class="bp">∣</span> <span class="bp">∏</span> <span class="n">i</span> <span class="k">in</span> <span class="n">s'</span><span class="o">,</span> <span class="n">i</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="o">:</span> <span class="n">p</span> <span class="bp">∣</span> <span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">convert</span> <span class="n">Nat.dvd_sub'</span> <span class="n">pdvd</span> <span class="n">this</span> <span class="n">simp</span> <span class="k">show</span> <span class="n">False</span> <span class="gr">sorry</span> </pre></div> </div> <p>We have thus seen two ways of saying that there are infinitely many primes: saying that they are not bounded by any <code class="docutils literal notranslate"><span class="pre">n</span></code>, and saying that they are not contained in any finite set <code class="docutils literal notranslate"><span class="pre">s</span></code>. The two proofs below show that these formulations are equivalent. In the second, in order to form <code class="docutils literal notranslate"><span class="pre">s.filter</span> <span class="pre">Q</span></code>, we have to assume that there is a procedure for deciding whether or not <code class="docutils literal notranslate"><span class="pre">Q</span></code> holds. Lean knows that there is a procedure for <code class="docutils literal notranslate"><span class="pre">Nat.Prime</span></code>. In general, if we use classical logic by writing <code class="docutils literal notranslate"><span class="pre">open</span> <span class="pre">Classical</span></code>, we can dispense with the assumption.</p> <p>In mathlib, <code class="docutils literal notranslate"><span class="pre">Finset.sup</span> <span class="pre">s</span> <span class="pre">f</span></code> denotes the supremum of the values of <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span></code> as <code class="docutils literal notranslate"><span class="pre">x</span></code> ranges over <code class="docutils literal notranslate"><span class="pre">s</span></code>, returning <code class="docutils literal notranslate"><span class="pre">0</span></code> in the case where <code class="docutils literal notranslate"><span class="pre">s</span></code> is empty and the codomain of <code class="docutils literal notranslate"><span class="pre">f</span></code> is <code class="docutils literal notranslate"><span class="pre">ℕ</span></code>. In the first proof, we use <code class="docutils literal notranslate"><span class="pre">s.sup</span> <span class="pre">id</span></code>, where <code class="docutils literal notranslate"><span class="pre">id</span></code> is the identity function, to refer to the maximum value in <code class="docutils literal notranslate"><span class="pre">s</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">bounded_of_ex_finset</span> <span class="o">(</span><span class="n">Q</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="kt">Prop</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="bp">∃</span> <span class="n">s</span> <span class="o">:</span> <span class="n">Finset</span> <span class="n">ℕ</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">k</span><span class="o">,</span> <span class="n">Q</span> <span class="n">k</span> <span class="bp">→</span> <span class="n">k</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">)</span> <span class="bp">→</span> <span class="bp">∃</span> <span class="n">n</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">k</span><span class="o">,</span> <span class="n">Q</span> <span class="n">k</span> <span class="bp">→</span> <span class="n">k</span> <span class="bp"><</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rintro</span> <span class="o">⟨</span><span class="n">s</span><span class="o">,</span> <span class="n">hs</span><span class="o">⟩</span> <span class="n">use</span> <span class="n">s.sup</span> <span class="n">id</span> <span class="bp">+</span> <span class="mi">1</span> <span class="n">intro</span> <span class="n">k</span> <span class="n">Qk</span> <span class="n">apply</span> <span class="n">Nat.lt_succ_of_le</span> <span class="k">show</span> <span class="n">id</span> <span class="n">k</span> <span class="bp">≤</span> <span class="n">s.sup</span> <span class="n">id</span> <span class="n">apply</span> <span class="n">le_sup</span> <span class="o">(</span><span class="n">hs</span> <span class="n">k</span> <span class="n">Qk</span><span class="o">)</span> <span class="kd">theorem</span> <span class="n">ex_finset_of_bounded</span> <span class="o">(</span><span class="n">Q</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="kt">Prop</span><span class="o">)</span> <span class="o">[</span><span class="n">DecidablePred</span> <span class="n">Q</span><span class="o">]</span> <span class="o">:</span> <span class="o">(</span><span class="bp">∃</span> <span class="n">n</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">k</span><span class="o">,</span> <span class="n">Q</span> <span class="n">k</span> <span class="bp">→</span> <span class="n">k</span> <span class="bp">≤</span> <span class="n">n</span><span class="o">)</span> <span class="bp">→</span> <span class="bp">∃</span> <span class="n">s</span> <span class="o">:</span> <span class="n">Finset</span> <span class="n">ℕ</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">k</span><span class="o">,</span> <span class="n">Q</span> <span class="n">k</span> <span class="bp">↔</span> <span class="n">k</span> <span class="bp">∈</span> <span class="n">s</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rintro</span> <span class="o">⟨</span><span class="n">n</span><span class="o">,</span> <span class="n">hn</span><span class="o">⟩</span> <span class="n">use</span> <span class="o">(</span><span class="n">range</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">))</span><span class="bp">.</span><span class="n">filter</span> <span class="n">Q</span> <span class="n">intro</span> <span class="n">k</span> <span class="n">simp</span> <span class="o">[</span><span class="n">Nat.lt_succ_iff</span><span class="o">]</span> <span class="n">exact</span> <span class="n">hn</span> <span class="n">k</span> </pre></div> </div> <p>A small variation on our second proof that there are infinitely many primes shows that there are infinitely many primes congruent to 3 modulo 4. The argument goes as follows. First, notice that if the product of two numbers <span class="math notranslate nohighlight">\(m\)</span> and <span class="math notranslate nohighlight">\(n\)</span> is equal to 3 modulo 4, then one of the two numbers is congruent to three modulo 4. After all, both have to be odd, and if they are both congruent to 1 modulo 4, so is their product. We can use this observation to show that if some number greater than 2 is congruent to 3 modulo 4, then that number has a prime divisor that is also congruent to 3 modulo 4.</p> <p>Now suppose there are only finitely many prime numbers congruent to 3 modulo 4, say, <span class="math notranslate nohighlight">\(p_1, \ldots, p_k\)</span>. Without loss of generality, we can assume that <span class="math notranslate nohighlight">\(p_1 = 3\)</span>. Consider the product <span class="math notranslate nohighlight">\(4 \prod_{i = 2}^k p_i + 3\)</span>. It is easy to see that this is congruent to 3 modulo 4, so it has a prime factor <span class="math notranslate nohighlight">\(p\)</span> congruent to 3 modulo 4. It can’t be the case that <span class="math notranslate nohighlight">\(p = 3\)</span>; since <span class="math notranslate nohighlight">\(p\)</span> divides <span class="math notranslate nohighlight">\(4 \prod_{i = 2}^k p_i + 3\)</span>, if <span class="math notranslate nohighlight">\(p\)</span> were equal to 3 then it would also divide <span class="math notranslate nohighlight">\(\prod_{i = 2}^k p_i\)</span>, which implies that <span class="math notranslate nohighlight">\(p\)</span> is equal to one of the <span class="math notranslate nohighlight">\(p_i\)</span> for <span class="math notranslate nohighlight">\(i = 2, \ldots, k\)</span>; and we have excluded 3 from this list. So <span class="math notranslate nohighlight">\(p\)</span> has to be one of the other elements <span class="math notranslate nohighlight">\(p_i\)</span>. But in that case, <span class="math notranslate nohighlight">\(p\)</span> divides <span class="math notranslate nohighlight">\(4 \prod_{i = 2}^k p_i\)</span> and hence 3, which contradicts the fact that it is not 3.</p> <p>In Lean, the notation <code class="docutils literal notranslate"><span class="pre">n</span> <span class="pre">%</span> <span class="pre">m</span></code>, read “<code class="docutils literal notranslate"><span class="pre">n</span></code> modulo <code class="docutils literal notranslate"><span class="pre">m</span></code>,” denotes the remainder of the division of <code class="docutils literal notranslate"><span class="pre">n</span></code> by <code class="docutils literal notranslate"><span class="pre">m</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="mi">27</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp">=</span> <span class="mi">3</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">norm_num</span> </pre></div> </div> <p>We can then render the statement “<code class="docutils literal notranslate"><span class="pre">n</span></code> is congruent to 3 modulo 4” as <code class="docutils literal notranslate"><span class="pre">n</span> <span class="pre">%</span> <span class="pre">4</span> <span class="pre">=</span> <span class="pre">3</span></code>. The following example and theorems sum up the facts about this function that we will need to use below. The first named theorem is another illustration of reasoning by a small number of cases. In the second named theorem, remember that the semicolon means that the subsequent tactic block is applied to both of the goals that result from the application of <code class="docutils literal notranslate"><span class="pre">two_le</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="mi">4</span> <span class="bp">*</span> <span class="n">n</span> <span class="bp">+</span> <span class="mi">3</span><span class="o">)</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp">=</span> <span class="mi">3</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">add_comm</span><span class="o">,</span> <span class="n">Nat.add_mul_mod_self_left</span><span class="o">]</span> <span class="n">norm_num</span> <span class="kd">theorem</span> <span class="n">mod_4_eq_3_or_mod_4_eq_3</span> <span class="o">{</span><span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">*</span> <span class="n">n</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp">=</span> <span class="mi">3</span><span class="o">)</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp">=</span> <span class="mi">3</span> <span class="bp">∨</span> <span class="n">n</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp">=</span> <span class="mi">3</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">revert</span> <span class="n">h</span> <span class="n">rw</span> <span class="o">[</span><span class="n">Nat.mul_mod</span><span class="o">]</span> <span class="k">have</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp"><</span> <span class="mi">4</span> <span class="o">:=</span> <span class="n">Nat.mod_lt</span> <span class="n">m</span> <span class="o">(</span><span class="kd">by</span> <span class="n">norm_num</span><span class="o">)</span> <span class="n">interval_cases</span> <span class="n">hm</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp"><;></span> <span class="n">simp</span> <span class="o">[</span><span class="n">hm</span><span class="o">]</span> <span class="k">have</span> <span class="o">:</span> <span class="n">n</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp"><</span> <span class="mi">4</span> <span class="o">:=</span> <span class="n">Nat.mod_lt</span> <span class="n">n</span> <span class="o">(</span><span class="kd">by</span> <span class="n">norm_num</span><span class="o">)</span> <span class="n">interval_cases</span> <span class="n">hn</span> <span class="o">:</span> <span class="n">n</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp"><;></span> <span class="n">simp</span> <span class="o">[</span><span class="n">hn</span><span class="o">]</span> <span class="kd">theorem</span> <span class="n">two_le_of_mod_4_eq_3</span> <span class="o">{</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">n</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp">=</span> <span class="mi">3</span><span class="o">)</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">≤</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">two_le</span> <span class="bp"><;></span> <span class="bp">·</span> <span class="n">intro</span> <span class="n">neq</span> <span class="n">rw</span> <span class="o">[</span><span class="n">neq</span><span class="o">]</span> <span class="n">at</span> <span class="n">h</span> <span class="n">norm_num</span> <span class="n">at</span> <span class="n">h</span> </pre></div> </div> <p>We will also need the following fact, which says that if <code class="docutils literal notranslate"><span class="pre">m</span></code> is a nontrivial divisor of <code class="docutils literal notranslate"><span class="pre">n</span></code>, then so is <code class="docutils literal notranslate"><span class="pre">n</span> <span class="pre">/</span> <span class="pre">m</span></code>. See if you can complete the proof using <code class="docutils literal notranslate"><span class="pre">Nat.div_dvd_of_dvd</span></code> and <code class="docutils literal notranslate"><span class="pre">Nat.div_lt_self</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">aux</span> <span class="o">{</span><span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">h₀</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">∣</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">h₁</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">≤</span> <span class="n">m</span><span class="o">)</span> <span class="o">(</span><span class="n">h₂</span> <span class="o">:</span> <span class="n">m</span> <span class="bp"><</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="n">n</span> <span class="bp">/</span> <span class="n">m</span> <span class="bp">∣</span> <span class="n">n</span> <span class="bp">∧</span> <span class="n">n</span> <span class="bp">/</span> <span class="n">m</span> <span class="bp"><</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Now put all the pieces together to prove that any number congruent to 3 modulo 4 has a prime divisor with that same property.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">exists_prime_factor_mod_4_eq_3</span> <span class="o">{</span><span class="n">n</span> <span class="o">:</span> <span class="n">Nat</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">n</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp">=</span> <span class="mi">3</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">p</span> <span class="o">:</span> <span class="n">Nat</span><span class="o">,</span> <span class="n">p.Prime</span> <span class="bp">∧</span> <span class="n">p</span> <span class="bp">∣</span> <span class="n">n</span> <span class="bp">∧</span> <span class="n">p</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp">=</span> <span class="mi">3</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">by_cases</span> <span class="n">np</span> <span class="o">:</span> <span class="n">n.Prime</span> <span class="bp">·</span> <span class="n">use</span> <span class="n">n</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">np</span><span class="o">,</span> <span class="n">dvd_rfl</span><span class="o">,</span> <span class="n">h</span><span class="o">⟩</span> <span class="n">induction'</span> <span class="n">n</span> <span class="n">using</span> <span class="n">Nat.strong_induction_on</span> <span class="k">with</span> <span class="n">n</span> <span class="n">ih</span> <span class="n">dsimp</span> <span class="n">at</span> <span class="n">ih</span> <span class="n">rw</span> <span class="o">[</span><span class="n">Nat.prime_def_lt</span><span class="o">]</span> <span class="n">at</span> <span class="n">np</span> <span class="n">push_neg</span> <span class="n">at</span> <span class="n">np</span> <span class="n">rcases</span> <span class="n">np</span> <span class="o">(</span><span class="n">two_le_of_mod_4_eq_3</span> <span class="n">h</span><span class="o">)</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">m</span><span class="o">,</span> <span class="n">mltn</span><span class="o">,</span> <span class="n">mdvdn</span><span class="o">,</span> <span class="n">mne1</span><span class="o">⟩</span> <span class="k">have</span> <span class="n">mge2</span> <span class="o">:</span> <span class="mi">2</span> <span class="bp">≤</span> <span class="n">m</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">two_le</span> <span class="n">_</span> <span class="n">mne1</span> <span class="n">intro</span> <span class="n">mz</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mz</span><span class="o">,</span> <span class="n">zero_dvd_iff</span><span class="o">]</span> <span class="n">at</span> <span class="n">mdvdn</span> <span class="n">linarith</span> <span class="k">have</span> <span class="n">neq</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">*</span> <span class="o">(</span><span class="n">n</span> <span class="bp">/</span> <span class="n">m</span><span class="o">)</span> <span class="bp">=</span> <span class="n">n</span> <span class="o">:=</span> <span class="n">Nat.mul_div_cancel'</span> <span class="n">mdvdn</span> <span class="k">have</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp">=</span> <span class="mi">3</span> <span class="bp">∨</span> <span class="n">n</span> <span class="bp">/</span> <span class="n">m</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp">=</span> <span class="mi">3</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">mod_4_eq_3_or_mod_4_eq_3</span> <span class="n">rw</span> <span class="o">[</span><span class="n">neq</span><span class="o">,</span> <span class="n">h</span><span class="o">]</span> <span class="n">cases'</span> <span class="n">this</span> <span class="k">with</span> <span class="n">h1</span> <span class="n">h1</span> <span class="bp">.</span> <span class="gr">sorry</span> <span class="bp">.</span> <span class="gr">sorry</span> </pre></div> </div> <p>We are in the home stretch. Given a set <code class="docutils literal notranslate"><span class="pre">s</span></code> of prime numbers, we need to talk about the result of removing 3 from that set, if it is present. The function <code class="docutils literal notranslate"><span class="pre">Finset.erase</span></code> handles that.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">s</span> <span class="o">:</span> <span class="n">Finset</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">∈</span> <span class="n">erase</span> <span class="n">s</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">≠</span> <span class="n">n</span> <span class="bp">∧</span> <span class="n">m</span> <span class="bp">∈</span> <span class="n">s</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rwa</span> <span class="o">[</span><span class="n">mem_erase</span><span class="o">]</span> <span class="n">at</span> <span class="n">h</span> <span class="kd">example</span> <span class="o">(</span><span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">s</span> <span class="o">:</span> <span class="n">Finset</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">∈</span> <span class="n">erase</span> <span class="n">s</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="n">m</span> <span class="bp">≠</span> <span class="n">n</span> <span class="bp">∧</span> <span class="n">m</span> <span class="bp">∈</span> <span class="n">s</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="n">at</span> <span class="n">h</span> <span class="n">assumption</span> </pre></div> </div> <p>We are now ready to prove that there are infinitely many primes congruent to 3 modulo 4. Fill in the missing parts below. Our solution uses <code class="docutils literal notranslate"><span class="pre">Nat.dvd_add_iff_left</span></code> and <code class="docutils literal notranslate"><span class="pre">Nat.dvd_sub'</span></code> along the way.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">primes_mod_4_eq_3_infinite</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">p</span> <span class="bp">></span> <span class="n">n</span><span class="o">,</span> <span class="n">Nat.Prime</span> <span class="n">p</span> <span class="bp">∧</span> <span class="n">p</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp">=</span> <span class="mi">3</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">by_contra</span> <span class="n">h</span> <span class="n">push_neg</span> <span class="n">at</span> <span class="n">h</span> <span class="n">cases'</span> <span class="n">h</span> <span class="k">with</span> <span class="n">n</span> <span class="n">hn</span> <span class="k">have</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">s</span> <span class="o">:</span> <span class="n">Finset</span> <span class="n">Nat</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">p</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">,</span> <span class="n">p.Prime</span> <span class="bp">∧</span> <span class="n">p</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp">=</span> <span class="mi">3</span> <span class="bp">↔</span> <span class="n">p</span> <span class="bp">∈</span> <span class="n">s</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">ex_finset_of_bounded</span> <span class="n">use</span> <span class="n">n</span> <span class="n">contrapose</span><span class="bp">!</span> <span class="n">hn</span> <span class="n">rcases</span> <span class="n">hn</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">p</span><span class="o">,</span> <span class="o">⟨</span><span class="n">pp</span><span class="o">,</span> <span class="n">p4</span><span class="o">⟩,</span> <span class="n">pltn</span><span class="o">⟩</span> <span class="n">exact</span> <span class="o">⟨</span><span class="n">p</span><span class="o">,</span> <span class="n">pltn</span><span class="o">,</span> <span class="n">pp</span><span class="o">,</span> <span class="n">p4</span><span class="o">⟩</span> <span class="n">cases'</span> <span class="n">this</span> <span class="k">with</span> <span class="n">s</span> <span class="n">hs</span> <span class="k">have</span> <span class="n">h₁</span> <span class="o">:</span> <span class="o">((</span><span class="mi">4</span> <span class="bp">*</span> <span class="bp">∏</span> <span class="n">i</span> <span class="k">in</span> <span class="n">erase</span> <span class="n">s</span> <span class="mi">3</span><span class="o">,</span> <span class="n">i</span><span class="o">)</span> <span class="bp">+</span> <span class="mi">3</span><span class="o">)</span> <span class="bp">%</span> <span class="mi">4</span> <span class="bp">=</span> <span class="mi">3</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="n">rcases</span> <span class="n">exists_prime_factor_mod_4_eq_3</span> <span class="n">h₁</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">p</span><span class="o">,</span> <span class="n">pp</span><span class="o">,</span> <span class="n">pdvd</span><span class="o">,</span> <span class="n">p4eq</span><span class="o">⟩</span> <span class="k">have</span> <span class="n">ps</span> <span class="o">:</span> <span class="n">p</span> <span class="bp">∈</span> <span class="n">s</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="n">pne3</span> <span class="o">:</span> <span class="n">p</span> <span class="bp">≠</span> <span class="mi">3</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="o">:</span> <span class="n">p</span> <span class="bp">∣</span> <span class="mi">4</span> <span class="bp">*</span> <span class="bp">∏</span> <span class="n">i</span> <span class="k">in</span> <span class="n">erase</span> <span class="n">s</span> <span class="mi">3</span><span class="o">,</span> <span class="n">i</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="o">:</span> <span class="n">p</span> <span class="bp">∣</span> <span class="mi">3</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="o">:</span> <span class="n">p</span> <span class="bp">=</span> <span class="mi">3</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="n">contradiction</span> </pre></div> </div> <p>If you managed to complete the proof, congratulations! This has been a serious feat of formalization.</p> </section> </section> </div> </div> <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> <a href="C04_Sets_and_Functions.html" class="btn btn-neutral float-left" title="4. Sets and Functions" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> <a href="C06_Structures.html" class="btn btn-neutral float-right" title="6. Structures" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> </div> <hr/> <div role="contentinfo"> <p>© Copyright 2020, Jeremy Avigad, Kevin Buzzard, Robert Y. Lewis, Patrick Massot.</p> </div> Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. </footer> </div> </div> </section> </div> <script> jQuery(function () { SphinxRtdTheme.Navigation.enable(true); }); </script> </body> </html>
-
-
html/C06_Structures.html (new)
-
@@ -0,0 +1,1569 @@<!DOCTYPE html> <html class="writer-html5" lang="en" > <head> <meta charset="utf-8" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>6. Structures — Mathematics in Lean 0.1 documentation</title> <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> <link rel="stylesheet" href="_static/css/custom.css" type="text/css" /> <link rel="shortcut icon" href="_static/favicon.ico"/> <!--[if lt IE 9]> <script src="_static/js/html5shiv.min.js"></script> <![endif]--> <script src="_static/jquery.js"></script> <script src="_static/_sphinx_javascript_frameworks_compat.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script src="_static/doctools.js"></script> <script src="_static/sphinx_highlight.js"></script> <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> <script src="_static/js/theme.js"></script> <link rel="index" title="Index" href="genindex.html" /> <link rel="search" title="Search" href="search.html" /> <link rel="next" title="7. Hierarchies" href="C07_Hierarchies.html" /> <link rel="prev" title="5. Number Theory" href="C05_Number_Theory.html" /> </head> <body class="wy-body-for-nav"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search" > <a href="index.html" class="icon icon-home"> Mathematics in Lean </a> <div role="search"> <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> <ul class="current"> <li class="toctree-l1"><a class="reference internal" href="C01_Introduction.html">1. Introduction</a></li> <li class="toctree-l1"><a class="reference internal" href="C02_Basics.html">2. Basics</a></li> <li class="toctree-l1"><a class="reference internal" href="C03_Logic.html">3. Logic</a></li> <li class="toctree-l1"><a class="reference internal" href="C04_Sets_and_Functions.html">4. Sets and Functions</a></li> <li class="toctree-l1"><a class="reference internal" href="C05_Number_Theory.html">5. Number Theory</a></li> <li class="toctree-l1 current"><a class="current reference internal" href="#">6. Structures</a><ul> <li class="toctree-l2"><a class="reference internal" href="#defining-structures">6.1. Defining structures</a></li> <li class="toctree-l2"><a class="reference internal" href="#algebraic-structures">6.2. Algebraic Structures</a></li> <li class="toctree-l2"><a class="reference internal" href="#building-the-gaussian-integers">6.3. Building the Gaussian Integers</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="C07_Hierarchies.html">7. Hierarchies</a></li> <li class="toctree-l1"><a class="reference internal" href="C08_Topology.html">8. Topology</a></li> <li class="toctree-l1"><a class="reference internal" href="C09_Differential_Calculus.html">9. Differential Calculus</a></li> </ul> <ul> <li class="toctree-l1"><a class="reference internal" href="genindex.html">Index</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="index.html">Mathematics in Lean</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="Page navigation"> <ul class="wy-breadcrumbs"> <li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li> <li class="breadcrumb-item active"><span class="section-number">6. </span>Structures</li> <li class="wy-breadcrumbs-aside"> <a href="_sources/C06_Structures.rst.txt" rel="nofollow"> View page source</a> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <section id="structures"> <span id="id1"></span><h1><span class="section-number">6. </span>Structures<a class="headerlink" href="#structures" title="Permalink to this heading"></a></h1> <p>Modern mathematics makes essential use of algebraic structures, which encapsulate patterns that can be instantiated in multiple settings. The subject provides various ways of defining such structures and constructing particular instances.</p> <p>Lean therefore provides corresponding ways of defining structures formally and working with them. You have already seen examples of algebraic structures in Lean, such as rings and lattices, which were discussed in <a class="reference internal" href="C02_Basics.html#basics"><span class="std std-numref">Chapter 2</span></a>. This chapter will explain the mysterious square bracket annotations that you saw there, <code class="docutils literal notranslate"><span class="pre">[Ring</span> <span class="pre">α]</span></code> and <code class="docutils literal notranslate"><span class="pre">[Lattice</span> <span class="pre">α]</span></code>. It will also show you how to define and use algebraic structures on your own.</p> <p>For more technical detail, you can consult <a class="reference external" href="https://leanprover.github.io/theorem_proving_in_lean/">Theorem Proving in Lean</a>, and a paper by Anne Baanen, <a class="reference external" href="https://arxiv.org/abs/2202.01629">Use and abuse of instance parameters in the Lean mathematical library</a>.</p> <section id="defining-structures"> <span id="section-structures"></span><h2><span class="section-number">6.1. </span>Defining structures<a class="headerlink" href="#defining-structures" title="Permalink to this heading"></a></h2> <p>In the broadest sense of the term, a <em>structure</em> is a specification of a collection of data, possibly with constraints that the data is required to satisfy. An <em>instance</em> of the structure is a particular bundle of data satisfying the constraints. For example, we can specify that a point is a tuple of three real numbers:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">@[ext]</span> <span class="kd">structure</span> <span class="n">Point</span> <span class="n">where</span> <span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="n">z</span> <span class="o">:</span> <span class="n">ℝ</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">@[ext]</span></code> annotation tells Lean to automatically generate theorems that can be used to prove that two instances of a structure are equal when their components are equal, a property known as <em>extensionality</em>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="n">Point.ext</span> <span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">Point</span><span class="o">)</span> <span class="o">(</span><span class="n">hx</span> <span class="o">:</span> <span class="n">a.x</span> <span class="bp">=</span> <span class="n">b.x</span><span class="o">)</span> <span class="o">(</span><span class="n">hy</span> <span class="o">:</span> <span class="n">a.y</span> <span class="bp">=</span> <span class="n">b.y</span><span class="o">)</span> <span class="o">(</span><span class="n">hz</span> <span class="o">:</span> <span class="n">a.z</span> <span class="bp">=</span> <span class="n">b.z</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ext</span> <span class="n">repeat'</span> <span class="n">assumption</span> </pre></div> </div> <p>We can then define particular instances of the <code class="docutils literal notranslate"><span class="pre">Point</span></code> structure. Lean provides multiple ways of doing that.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">myPoint1</span> <span class="o">:</span> <span class="n">Point</span> <span class="n">where</span> <span class="n">x</span> <span class="o">:=</span> <span class="mi">2</span> <span class="n">y</span> <span class="o">:=</span> <span class="bp">-</span><span class="mi">1</span> <span class="n">z</span> <span class="o">:=</span> <span class="mi">4</span> <span class="kd">def</span> <span class="n">myPoint2</span> <span class="o">:</span> <span class="n">Point</span> <span class="o">:=</span> <span class="o">⟨</span><span class="mi">2</span><span class="o">,</span> <span class="bp">-</span><span class="mi">1</span><span class="o">,</span> <span class="mi">4</span><span class="o">⟩</span> <span class="kd">def</span> <span class="n">myPoint3</span> <span class="o">:=</span> <span class="n">Point.mk</span> <span class="mi">2</span> <span class="o">(</span><span class="bp">-</span><span class="mi">1</span><span class="o">)</span> <span class="mi">4</span> </pre></div> </div> <p>In the first example, the fields of the structure are named explicitly. The function <code class="docutils literal notranslate"><span class="pre">Point.mk</span></code> referred to in the definition of <code class="docutils literal notranslate"><span class="pre">myPoint3</span></code> is known as the <em>constructor</em> for the <code class="docutils literal notranslate"><span class="pre">Point</span></code> structure, because it serves to construct elements. You can specify a different name if you want, like <code class="docutils literal notranslate"><span class="pre">build</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">structure</span> <span class="n">Point'</span> <span class="n">where</span> <span class="n">build</span> <span class="o">::</span> <span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="n">z</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="k">#check</span> <span class="n">Point'.build</span> <span class="mi">2</span> <span class="o">(</span><span class="bp">-</span><span class="mi">1</span><span class="o">)</span> <span class="mi">4</span> </pre></div> </div> <p>The next two examples show how to define functions on structures. Whereas the second example makes the <code class="docutils literal notranslate"><span class="pre">Point.mk</span></code> constructor explicit, the first example uses an anonymous constructor for brevity. Lean can infer the relevant constructor from the indicated type of <code class="docutils literal notranslate"><span class="pre">add</span></code>. It is conventional to put definitions and theorems associated with a structure like <code class="docutils literal notranslate"><span class="pre">Point</span></code> in a namespace with the same name. In the example below, because we have opened the <code class="docutils literal notranslate"><span class="pre">Point</span></code> namespace, the full name of <code class="docutils literal notranslate"><span class="pre">add</span></code> is <code class="docutils literal notranslate"><span class="pre">Point.add</span></code>. When the namespace is not open, we have to use the full name. But remember that it is often convenient to use anonymous projection notation, which allows us to write <code class="docutils literal notranslate"><span class="pre">a.add</span> <span class="pre">b</span></code> instead of <code class="docutils literal notranslate"><span class="pre">Point.add</span> <span class="pre">a</span> <span class="pre">b</span></code>. Lean interprets the former as the latter because <code class="docutils literal notranslate"><span class="pre">a</span></code> has type <code class="docutils literal notranslate"><span class="pre">Point</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">namespace</span> <span class="n">Point</span> <span class="kd">def</span> <span class="n">add</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">Point</span><span class="o">)</span> <span class="o">:</span> <span class="n">Point</span> <span class="o">:=</span> <span class="o">⟨</span><span class="n">a.x</span> <span class="bp">+</span> <span class="n">b.x</span><span class="o">,</span> <span class="n">a.y</span> <span class="bp">+</span> <span class="n">b.y</span><span class="o">,</span> <span class="n">a.z</span> <span class="bp">+</span> <span class="n">b.z</span><span class="o">⟩</span> <span class="kd">def</span> <span class="n">add'</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">Point</span><span class="o">)</span> <span class="o">:</span> <span class="n">Point</span> <span class="n">where</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">a.x</span> <span class="bp">+</span> <span class="n">b.x</span> <span class="n">y</span> <span class="o">:=</span> <span class="n">a.y</span> <span class="bp">+</span> <span class="n">b.y</span> <span class="n">z</span> <span class="o">:=</span> <span class="n">a.z</span> <span class="bp">+</span> <span class="n">b.z</span> <span class="k">#check</span> <span class="n">add</span> <span class="n">myPoint1</span> <span class="n">myPoint2</span> <span class="k">#check</span> <span class="n">myPoint1.add</span> <span class="n">myPoint2</span> <span class="kd">end</span> <span class="n">Point</span> <span class="k">#check</span> <span class="n">Point.add</span> <span class="n">myPoint1</span> <span class="n">myPoint2</span> <span class="k">#check</span> <span class="n">myPoint1.add</span> <span class="n">myPoint2</span> </pre></div> </div> <p>Below we will continue to put definitions in the relevant namespace, but we will leave the namespacing commands out of the quoted snippets. To prove properties of the addition function, we can use <code class="docutils literal notranslate"><span class="pre">rw</span></code> to expand the definition and <code class="docutils literal notranslate"><span class="pre">ext</span></code> to reduce an equation between two elements of the structure to equations between the components. Below we use the <code class="docutils literal notranslate"><span class="pre">protected</span></code> keyword so that the name of the theorem is <code class="docutils literal notranslate"><span class="pre">Point.add_comm</span></code>, even when the namespace is open. This is helpful when we want to avoid ambiguity with a generic theorem like <code class="docutils literal notranslate"><span class="pre">add_comm</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">protected</span> <span class="kd">theorem</span> <span class="n">add_comm</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">Point</span><span class="o">)</span> <span class="o">:</span> <span class="n">add</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">add</span> <span class="n">b</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">add</span><span class="o">,</span> <span class="n">add</span><span class="o">]</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">dsimp</span> <span class="n">repeat'</span> <span class="n">apply</span> <span class="n">add_comm</span> <span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">Point</span><span class="o">)</span> <span class="o">:</span> <span class="n">add</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">add</span> <span class="n">b</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="o">[</span><span class="n">add</span><span class="o">,</span> <span class="n">add_comm</span><span class="o">]</span> </pre></div> </div> <p>Because Lean can unfold definitions and simplify projections internally, sometimes the equations we want hold definitionally.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">add_x</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">Point</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">a.add</span> <span class="n">b</span><span class="o">)</span><span class="bp">.</span><span class="n">x</span> <span class="bp">=</span> <span class="n">a.x</span> <span class="bp">+</span> <span class="n">b.x</span> <span class="o">:=</span> <span class="n">rfl</span> </pre></div> </div> <p>It is also possible to define functions on structures using pattern matching, in a manner similar to the way we defined recursive functions in <a class="reference internal" href="C05_Number_Theory.html#section-induction-and-recursion"><span class="std std-numref">Section 5.2</span></a>. The definitions <code class="docutils literal notranslate"><span class="pre">addAlt</span></code> and <code class="docutils literal notranslate"><span class="pre">addAlt'</span></code> below are essentially the same; the only difference is that we use anonymous constructor notation in the second. Although it is sometimes convenient to define functions this way, the definitional properties are not as convenient. For example, the expressions <code class="docutils literal notranslate"><span class="pre">addAlt</span> <span class="pre">a</span> <span class="pre">b</span></code> and <code class="docutils literal notranslate"><span class="pre">addAlt'</span> <span class="pre">a</span> <span class="pre">b</span></code> cannot be simplified until we decompose <code class="docutils literal notranslate"><span class="pre">a</span></code> and <code class="docutils literal notranslate"><span class="pre">b</span></code> into components, which we can do with <code class="docutils literal notranslate"><span class="pre">cases</span></code>, <code class="docutils literal notranslate"><span class="pre">rcases</span></code>, etc.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">addAlt</span> <span class="o">:</span> <span class="n">Point</span> <span class="bp">→</span> <span class="n">Point</span> <span class="bp">→</span> <span class="n">Point</span> <span class="bp">|</span> <span class="n">Point.mk</span> <span class="n">x₁</span> <span class="n">y₁</span> <span class="n">z₁</span><span class="o">,</span> <span class="n">Point.mk</span> <span class="n">x₂</span> <span class="n">y₂</span> <span class="n">z₂</span> <span class="bp">=></span> <span class="o">⟨</span><span class="n">x₁</span> <span class="bp">+</span> <span class="n">x₂</span><span class="o">,</span> <span class="n">y₁</span> <span class="bp">+</span> <span class="n">y₂</span><span class="o">,</span> <span class="n">z₁</span> <span class="bp">+</span> <span class="n">z₂</span><span class="o">⟩</span> <span class="kd">def</span> <span class="n">addAlt'</span> <span class="o">:</span> <span class="n">Point</span> <span class="bp">→</span> <span class="n">Point</span> <span class="bp">→</span> <span class="n">Point</span> <span class="bp">|</span> <span class="o">⟨</span><span class="n">x₁</span><span class="o">,</span> <span class="n">y₁</span><span class="o">,</span> <span class="n">z₁</span><span class="o">⟩,</span> <span class="o">⟨</span><span class="n">x₂</span><span class="o">,</span> <span class="n">y₂</span><span class="o">,</span> <span class="n">z₂</span><span class="o">⟩</span> <span class="bp">=></span> <span class="o">⟨</span><span class="n">x₁</span> <span class="bp">+</span> <span class="n">x₂</span><span class="o">,</span> <span class="n">y₁</span> <span class="bp">+</span> <span class="n">y₂</span><span class="o">,</span> <span class="n">z₁</span> <span class="bp">+</span> <span class="n">z₂</span><span class="o">⟩</span> <span class="kd">theorem</span> <span class="n">addAlt_x</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">Point</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">a.addAlt</span> <span class="n">b</span><span class="o">)</span><span class="bp">.</span><span class="n">x</span> <span class="bp">=</span> <span class="n">a.x</span> <span class="bp">+</span> <span class="n">b.x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">cases</span> <span class="n">a</span> <span class="n">cases</span> <span class="n">b</span> <span class="n">rfl</span> <span class="kd">theorem</span> <span class="n">addAlt_comm</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">Point</span><span class="o">)</span> <span class="o">:</span> <span class="n">addAlt</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">addAlt</span> <span class="n">b</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rcases</span> <span class="n">a</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">xa</span><span class="o">,</span> <span class="n">ya</span><span class="o">,</span> <span class="n">za</span><span class="o">⟩</span> <span class="n">rcases</span> <span class="n">b</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">xb</span><span class="o">,</span> <span class="n">yb</span><span class="o">,</span> <span class="n">zb</span><span class="o">⟩</span> <span class="n">rw</span> <span class="o">[</span><span class="n">addAlt</span><span class="o">,</span> <span class="n">addAlt</span><span class="o">]</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">dsimp</span> <span class="n">apply</span> <span class="n">add_comm</span> <span class="n">repeat'</span> <span class="n">apply</span> <span class="n">add_comm</span> <span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">Point</span><span class="o">)</span> <span class="o">:</span> <span class="n">addAlt</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">addAlt</span> <span class="n">b</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rcases</span> <span class="n">a</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">xa</span><span class="o">,</span> <span class="n">ya</span><span class="o">,</span> <span class="n">za</span><span class="o">⟩</span> <span class="n">rcases</span> <span class="n">b</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">xb</span><span class="o">,</span> <span class="n">yb</span><span class="o">,</span> <span class="n">zb</span><span class="o">⟩</span> <span class="n">simp</span> <span class="o">[</span><span class="n">addAlt</span><span class="o">,</span> <span class="n">add_comm</span><span class="o">]</span> <span class="kd">example</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">Point</span><span class="o">,</span> <span class="n">addAlt</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">addAlt</span> <span class="n">b</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rintro</span> <span class="o">⟨</span><span class="n">xa</span><span class="o">,</span> <span class="n">ya</span><span class="o">,</span> <span class="n">za</span><span class="o">⟩</span> <span class="o">⟨</span><span class="n">xb</span><span class="o">,</span> <span class="n">yb</span><span class="o">,</span> <span class="n">zb</span><span class="o">⟩</span> <span class="n">simp</span> <span class="o">[</span><span class="n">addAlt</span><span class="o">,</span> <span class="n">add_comm</span><span class="o">]</span> <span class="kd">example</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">Point</span><span class="o">,</span> <span class="n">add</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">add</span> <span class="n">b</span> <span class="n">a</span> <span class="o">:=</span> <span class="k">fun</span> <span class="o">⟨</span><span class="n">xa</span><span class="o">,</span> <span class="n">ya</span><span class="o">,</span> <span class="n">za</span><span class="o">⟩</span> <span class="o">⟨</span><span class="n">xb</span><span class="o">,</span> <span class="n">yb</span><span class="o">,</span> <span class="n">zb</span><span class="o">⟩</span> <span class="bp">=></span> <span class="kd">by</span> <span class="n">simp</span> <span class="o">[</span><span class="n">add</span><span class="o">,</span> <span class="n">add_comm</span><span class="o">]</span> </pre></div> </div> <p>Mathematical constructions often involve taking apart bundled information and putting it together again in different ways. It therefore makes sense that Lean and mathlib offer so many ways of doing this efficiently. As an exercise, try proving that <code class="docutils literal notranslate"><span class="pre">Point.add</span></code> is associative. Then define scalar multiplication for a point and show that it distributes over addition.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">protected</span> <span class="kd">theorem</span> <span class="n">add_assoc</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">Point</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">a.add</span> <span class="n">b</span><span class="o">)</span><span class="bp">.</span><span class="n">add</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">a.add</span> <span class="o">(</span><span class="n">b.add</span> <span class="n">c</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">def</span> <span class="n">smul</span> <span class="o">(</span><span class="n">r</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">Point</span><span class="o">)</span> <span class="o">:</span> <span class="n">Point</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">smul_distrib</span> <span class="o">(</span><span class="n">r</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">Point</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">smul</span> <span class="n">r</span> <span class="n">a</span><span class="o">)</span><span class="bp">.</span><span class="n">add</span> <span class="o">(</span><span class="n">smul</span> <span class="n">r</span> <span class="n">b</span><span class="o">)</span> <span class="bp">=</span> <span class="n">smul</span> <span class="n">r</span> <span class="o">(</span><span class="n">a.add</span> <span class="n">b</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Using structures is only the first step on the road to algebraic abstraction. We don’t yet have a way to link <code class="docutils literal notranslate"><span class="pre">Point.add</span></code> to the generic <code class="docutils literal notranslate"><span class="pre">+</span></code> symbol, or to connect <code class="docutils literal notranslate"><span class="pre">Point.add_comm</span></code> and <code class="docutils literal notranslate"><span class="pre">Point.add_assoc</span></code> to the generic <code class="docutils literal notranslate"><span class="pre">add_comm</span></code> and <code class="docutils literal notranslate"><span class="pre">add_assoc</span></code> theorems. These tasks belong to the <em>algebraic</em> aspect of using structures, and we will explain how to carry them out in the next section. For now, just think of a structure as a way of bundling together objects and information.</p> <p>It is especially useful that a structure can specify not only data types but also constraints that the data must satisfy. In Lean, the latter are represented as fields of type <code class="docutils literal notranslate"><span class="pre">Prop</span></code>. For example, the <em>standard 2-simplex</em> is defined to be the set of points <span class="math notranslate nohighlight">\((x, y, z)\)</span> satisfying <span class="math notranslate nohighlight">\(x ≥ 0\)</span>, <span class="math notranslate nohighlight">\(y ≥ 0\)</span>, <span class="math notranslate nohighlight">\(z ≥ 0\)</span>, and <span class="math notranslate nohighlight">\(x + y + z = 1\)</span>. If you are not familiar with the notion, you should draw a picture, and convince yourself that this set is the equilateral triangle in three-space with vertices <span class="math notranslate nohighlight">\((1, 0, 0)\)</span>, <span class="math notranslate nohighlight">\((0, 1, 0)\)</span>, and <span class="math notranslate nohighlight">\((0, 0, 1)\)</span>, together with its interior. We can represent it in Lean as follows:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">structure</span> <span class="n">StandardTwoSimplex</span> <span class="n">where</span> <span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="n">z</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="n">x_nonneg</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">x</span> <span class="n">y_nonneg</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">y</span> <span class="n">z_nonneg</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">z</span> <span class="n">sum_eq</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">y</span> <span class="bp">+</span> <span class="n">z</span> <span class="bp">=</span> <span class="mi">1</span> </pre></div> </div> <p>Notice that the last four fields refer to <code class="docutils literal notranslate"><span class="pre">x</span></code>, <code class="docutils literal notranslate"><span class="pre">y</span></code>, and <code class="docutils literal notranslate"><span class="pre">z</span></code>, that is, the first three fields. We can define a map from the two-simplex to itself that swaps <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code>:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">swapXy</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">StandardTwoSimplex</span><span class="o">)</span> <span class="o">:</span> <span class="n">StandardTwoSimplex</span> <span class="n">where</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">a.y</span> <span class="n">y</span> <span class="o">:=</span> <span class="n">a.x</span> <span class="n">z</span> <span class="o">:=</span> <span class="n">a.z</span> <span class="n">x_nonneg</span> <span class="o">:=</span> <span class="n">a.y_nonneg</span> <span class="n">y_nonneg</span> <span class="o">:=</span> <span class="n">a.x_nonneg</span> <span class="n">z_nonneg</span> <span class="o">:=</span> <span class="n">a.z_nonneg</span> <span class="n">sum_eq</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">add_comm</span> <span class="n">a.y</span> <span class="n">a.x</span><span class="o">,</span> <span class="n">a.sum_eq</span><span class="o">]</span> </pre></div> </div> <p>More interestingly, we can compute the midpoint of two points on the simplex. We have added the phrase <code class="docutils literal notranslate"><span class="pre">noncomputable</span> <span class="pre">section</span></code> at the beginning of this file in order to use division on the real numbers.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">noncomputable</span> <span class="kn">section</span> <span class="kd">def</span> <span class="n">midpoint</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">StandardTwoSimplex</span><span class="o">)</span> <span class="o">:</span> <span class="n">StandardTwoSimplex</span> <span class="n">where</span> <span class="n">x</span> <span class="o">:=</span> <span class="o">(</span><span class="n">a.x</span> <span class="bp">+</span> <span class="n">b.x</span><span class="o">)</span> <span class="bp">/</span> <span class="mi">2</span> <span class="n">y</span> <span class="o">:=</span> <span class="o">(</span><span class="n">a.y</span> <span class="bp">+</span> <span class="n">b.y</span><span class="o">)</span> <span class="bp">/</span> <span class="mi">2</span> <span class="n">z</span> <span class="o">:=</span> <span class="o">(</span><span class="n">a.z</span> <span class="bp">+</span> <span class="n">b.z</span><span class="o">)</span> <span class="bp">/</span> <span class="mi">2</span> <span class="n">x_nonneg</span> <span class="o">:=</span> <span class="n">div_nonneg</span> <span class="o">(</span><span class="n">add_nonneg</span> <span class="n">a.x_nonneg</span> <span class="n">b.x_nonneg</span><span class="o">)</span> <span class="o">(</span><span class="kd">by</span> <span class="n">norm_num</span><span class="o">)</span> <span class="n">y_nonneg</span> <span class="o">:=</span> <span class="n">div_nonneg</span> <span class="o">(</span><span class="n">add_nonneg</span> <span class="n">a.y_nonneg</span> <span class="n">b.y_nonneg</span><span class="o">)</span> <span class="o">(</span><span class="kd">by</span> <span class="n">norm_num</span><span class="o">)</span> <span class="n">z_nonneg</span> <span class="o">:=</span> <span class="n">div_nonneg</span> <span class="o">(</span><span class="n">add_nonneg</span> <span class="n">a.z_nonneg</span> <span class="n">b.z_nonneg</span><span class="o">)</span> <span class="o">(</span><span class="kd">by</span> <span class="n">norm_num</span><span class="o">)</span> <span class="n">sum_eq</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">field_simp</span><span class="bp">;</span> <span class="n">linarith</span> <span class="o">[</span><span class="n">a.sum_eq</span><span class="o">,</span> <span class="n">b.sum_eq</span><span class="o">]</span> </pre></div> </div> <p>Here we have established <code class="docutils literal notranslate"><span class="pre">x_nonneg</span></code>, <code class="docutils literal notranslate"><span class="pre">y_nonneg</span></code>, and <code class="docutils literal notranslate"><span class="pre">z_nonneg</span></code> with concise proof terms, but establish <code class="docutils literal notranslate"><span class="pre">sum_eq</span></code> in tactic mode, using <code class="docutils literal notranslate"><span class="pre">by</span></code>.</p> <p>Given a parameter <span class="math notranslate nohighlight">\(\lambda\)</span> satisfying <span class="math notranslate nohighlight">\(0 \le \lambda \le 1\)</span>, we can take the weighted average <span class="math notranslate nohighlight">\(\lambda a + (1 - \lambda) b\)</span> of two points <span class="math notranslate nohighlight">\(a\)</span> and <span class="math notranslate nohighlight">\(b\)</span> in the standard 2-simplex. We challenge you to define that function, in analogy to the <code class="docutils literal notranslate"><span class="pre">midpoint</span></code> function above.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">weightedAverage</span> <span class="o">(</span><span class="n">lambda</span> <span class="o">:</span> <span class="n">Real</span><span class="o">)</span> <span class="o">(</span><span class="n">lambda_nonneg</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">lambda</span><span class="o">)</span> <span class="o">(</span><span class="n">lambda_le</span> <span class="o">:</span> <span class="n">lambda</span> <span class="bp">≤</span> <span class="mi">1</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">StandardTwoSimplex</span><span class="o">)</span> <span class="o">:</span> <span class="n">StandardTwoSimplex</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>Structures can depend on parameters. For example, we can generalize the standard 2-simplex to the standard <span class="math notranslate nohighlight">\(n\)</span>-simplex for any <span class="math notranslate nohighlight">\(n\)</span>. At this stage, you don’t have to know anything about the type <cite>Fin n</cite> except that it has <span class="math notranslate nohighlight">\(n\)</span> elements, and that Lean knows how to sum over it.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">open</span> <span class="n">BigOperators</span> <span class="kd">structure</span> <span class="n">StandardSimplex</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="n">where</span> <span class="n">V</span> <span class="o">:</span> <span class="n">Fin</span> <span class="n">n</span> <span class="bp">→</span> <span class="n">ℝ</span> <span class="n">NonNeg</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">i</span> <span class="o">:</span> <span class="n">Fin</span> <span class="n">n</span><span class="o">,</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">V</span> <span class="n">i</span> <span class="n">sum_eq_one</span> <span class="o">:</span> <span class="o">(</span><span class="bp">∑</span> <span class="n">i</span><span class="o">,</span> <span class="n">V</span> <span class="n">i</span><span class="o">)</span> <span class="bp">=</span> <span class="mi">1</span> <span class="kn">namespace</span> <span class="n">StandardSimplex</span> <span class="kd">def</span> <span class="n">midpoint</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">StandardSimplex</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="n">StandardSimplex</span> <span class="n">n</span> <span class="n">where</span> <span class="n">V</span> <span class="n">i</span> <span class="o">:=</span> <span class="o">(</span><span class="n">a.V</span> <span class="n">i</span> <span class="bp">+</span> <span class="n">b.V</span> <span class="n">i</span><span class="o">)</span> <span class="bp">/</span> <span class="mi">2</span> <span class="n">NonNeg</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">i</span> <span class="n">apply</span> <span class="n">div_nonneg</span> <span class="bp">·</span> <span class="n">linarith</span> <span class="o">[</span><span class="n">a.NonNeg</span> <span class="n">i</span><span class="o">,</span> <span class="n">b.NonNeg</span> <span class="n">i</span><span class="o">]</span> <span class="n">norm_num</span> <span class="n">sum_eq_one</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="o">[</span><span class="n">div_eq_mul_inv</span><span class="o">,</span> <span class="bp">←</span> <span class="n">Finset.sum_mul</span><span class="o">,</span> <span class="n">Finset.sum_add_distrib</span><span class="o">,</span> <span class="n">a.sum_eq_one</span><span class="o">,</span> <span class="n">b.sum_eq_one</span><span class="o">]</span> <span class="n">field_simp</span> <span class="kd">end</span> <span class="n">StandardSimplex</span> </pre></div> </div> <p>As an exercise, see if you can define the weighted average of two points in the standard <span class="math notranslate nohighlight">\(n\)</span>-simplex. You can use <code class="docutils literal notranslate"><span class="pre">Finset.sum_add_distrib</span></code> and <code class="docutils literal notranslate"><span class="pre">Finset.mul_sum</span></code> to manipulate the relevant sums. We have seen that structures can be used to bundle together data and properties. Interestingly, they can also be used to bundle together properties without the data. For example, the next structure, <code class="docutils literal notranslate"><span class="pre">IsLinear</span></code>, bundles together the two components of linearity.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">structure</span> <span class="n">IsLinear</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="n">where</span> <span class="n">is_additive</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="n">y</span><span class="o">,</span> <span class="n">f</span> <span class="o">(</span><span class="n">x</span> <span class="bp">+</span> <span class="n">y</span><span class="o">)</span> <span class="bp">=</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">f</span> <span class="n">y</span> <span class="n">preserves_mul</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="n">c</span><span class="o">,</span> <span class="n">f</span> <span class="o">(</span><span class="n">c</span> <span class="bp">*</span> <span class="n">x</span><span class="o">)</span> <span class="bp">=</span> <span class="n">c</span> <span class="bp">*</span> <span class="n">f</span> <span class="n">x</span> <span class="kn">section</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">linf</span> <span class="o">:</span> <span class="n">IsLinear</span> <span class="n">f</span><span class="o">)</span> <span class="k">#check</span> <span class="n">linf.is_additive</span> <span class="k">#check</span> <span class="n">linf.preserves_mul</span> <span class="kd">end</span> </pre></div> </div> <p>It is worth pointing out that structures are not the only way to bundle together data. The <code class="docutils literal notranslate"><span class="pre">Point</span></code> data structure can be defined using the generic type product, and <code class="docutils literal notranslate"><span class="pre">IsLinear</span></code> can be defined with a simple <code class="docutils literal notranslate"><span class="pre">and</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">Point''</span> <span class="o">:=</span> <span class="n">ℝ</span> <span class="bp">×</span> <span class="n">ℝ</span> <span class="bp">×</span> <span class="n">ℝ</span> <span class="kd">def</span> <span class="n">IsLinear'</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:=</span> <span class="o">(</span><span class="bp">∀</span> <span class="n">x</span> <span class="n">y</span><span class="o">,</span> <span class="n">f</span> <span class="o">(</span><span class="n">x</span> <span class="bp">+</span> <span class="n">y</span><span class="o">)</span> <span class="bp">=</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">f</span> <span class="n">y</span><span class="o">)</span> <span class="bp">∧</span> <span class="bp">∀</span> <span class="n">x</span> <span class="n">c</span><span class="o">,</span> <span class="n">f</span> <span class="o">(</span><span class="n">c</span> <span class="bp">*</span> <span class="n">x</span><span class="o">)</span> <span class="bp">=</span> <span class="n">c</span> <span class="bp">*</span> <span class="n">f</span> <span class="n">x</span> </pre></div> </div> <p>Generic type constructions can even be used in place of structures with dependencies between their components. For example, the <em>subtype</em> construction combines a piece of data with a property. You can think of the type <code class="docutils literal notranslate"><span class="pre">PReal</span></code> in the next example as being the type of positive real numbers. Any <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">:</span> <span class="pre">PReal</span></code> has two components: the value, and the property of being positive. You can access these components as <code class="docutils literal notranslate"><span class="pre">x.val</span></code>, which has type <code class="docutils literal notranslate"><span class="pre">ℝ</span></code>, and <code class="docutils literal notranslate"><span class="pre">x.property</span></code>, which represents the fact <code class="docutils literal notranslate"><span class="pre">0</span> <span class="pre"><</span> <span class="pre">x.val</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">PReal</span> <span class="o">:=</span> <span class="o">{</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">//</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">y</span> <span class="o">}</span> <span class="kn">section</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">PReal</span><span class="o">)</span> <span class="k">#check</span> <span class="n">x.val</span> <span class="k">#check</span> <span class="n">x.property</span> <span class="k">#check</span> <span class="n">x.1</span> <span class="k">#check</span> <span class="n">x.2</span> <span class="kd">end</span> </pre></div> </div> <p>We could have used subtypes to define the standard 2-simplex, as well as the standard <span class="math notranslate nohighlight">\(n\)</span>-simplex for an arbitrary <span class="math notranslate nohighlight">\(n\)</span>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">StandardTwoSimplex'</span> <span class="o">:=</span> <span class="o">{</span> <span class="n">p</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">×</span> <span class="n">ℝ</span> <span class="bp">×</span> <span class="n">ℝ</span> <span class="bp">//</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">p.1</span> <span class="bp">∧</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">p.2.1</span> <span class="bp">∧</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">p.2.2</span> <span class="bp">∧</span> <span class="n">p.1</span> <span class="bp">+</span> <span class="n">p.2.1</span> <span class="bp">+</span> <span class="n">p.2.2</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">}</span> <span class="kd">def</span> <span class="n">StandardSimplex'</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">:=</span> <span class="o">{</span> <span class="n">v</span> <span class="o">:</span> <span class="n">Fin</span> <span class="n">n</span> <span class="bp">→</span> <span class="n">ℝ</span> <span class="bp">//</span> <span class="o">(</span><span class="bp">∀</span> <span class="n">i</span> <span class="o">:</span> <span class="n">Fin</span> <span class="n">n</span><span class="o">,</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">v</span> <span class="n">i</span><span class="o">)</span> <span class="bp">∧</span> <span class="o">(</span><span class="bp">∑</span> <span class="n">i</span><span class="o">,</span> <span class="n">v</span> <span class="n">i</span><span class="o">)</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">}</span> </pre></div> </div> <p>Similarly, <em>Sigma types</em> are generalizations of ordered pairs, whereby the type of the second component depends on the type of the first.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">StdSimplex</span> <span class="o">:=</span> <span class="bp">Σ</span> <span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">,</span> <span class="n">StandardSimplex</span> <span class="n">n</span> <span class="kn">section</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">s</span> <span class="o">:</span> <span class="n">StdSimplex</span><span class="o">)</span> <span class="k">#check</span> <span class="n">s.fst</span> <span class="k">#check</span> <span class="n">s.snd</span> <span class="k">#check</span> <span class="n">s.1</span> <span class="k">#check</span> <span class="n">s.2</span> <span class="kd">end</span> </pre></div> </div> <p>Given <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">:</span> <span class="pre">StdSimplex</span></code>, the first component <code class="docutils literal notranslate"><span class="pre">s.fst</span></code> is a natural number, and the second component is an element of the corresponding simplex <code class="docutils literal notranslate"><span class="pre">StandardSimplex</span> <span class="pre">s.fst</span></code>. The difference between a Sigma type and a subtype is that the second component of a Sigma type is data rather than a proposition.</p> <p>But even though we can use products, subtypes, and Sigma types instead of structures, using structures has a number of advantages. Defining a structure abstracts away the underlying representation and provides custom names for the functions that access the components. This makes proofs more robust: proofs that rely only on the interface to a structure will generally continue to work when we change the definition, as long as we redefine the old accessors in terms of the new definition. Moreover, as we are about to see, Lean provides support for weaving structures together into a rich, interconnected hierarchy, and for managing the interactions between them.</p> </section> <section id="algebraic-structures"> <span id="section-algebraic-structures"></span><h2><span class="section-number">6.2. </span>Algebraic Structures<a class="headerlink" href="#algebraic-structures" title="Permalink to this heading"></a></h2> <p>To clarify what we mean by the phrase <em>algebraic structure</em>, it will help to consider some examples.</p> <ol class="arabic simple"> <li><p>A <em>partially ordered set</em> consists of a set <span class="math notranslate nohighlight">\(P\)</span> and a binary relation <span class="math notranslate nohighlight">\(\le\)</span> on <span class="math notranslate nohighlight">\(P\)</span> that is transitive and antireflexive.</p></li> <li><p>A <em>group</em> consists of a set <span class="math notranslate nohighlight">\(G\)</span> with an associative binary operation, an identity element <span class="math notranslate nohighlight">\(1\)</span>, and a function <span class="math notranslate nohighlight">\(g \mapsto g^{-1}\)</span> that returns an inverse for each <span class="math notranslate nohighlight">\(g\)</span> in <span class="math notranslate nohighlight">\(G\)</span>. A group is <em>abelian</em> or <em>commutative</em> if the operation is commutative.</p></li> <li><p>A <em>lattice</em> is a partially ordered set with meets and joins.</p></li> <li><p>A <em>ring</em> consists of an (additively written) abelian group <span class="math notranslate nohighlight">\((R, +, 0, x \mapsto -x)\)</span> together with an associative multiplication operation <span class="math notranslate nohighlight">\(\cdot\)</span> and an identity <span class="math notranslate nohighlight">\(1\)</span>, such that multiplication distributes over addition. A ring is <em>commutative</em> if the multiplication is commutative.</p></li> <li><p>An <em>ordered ring</em> <span class="math notranslate nohighlight">\((R, +, 0, -, \cdot, 1, \le)\)</span> consists of a ring together with a partial order on its elements, such that <span class="math notranslate nohighlight">\(a \le b\)</span> implies <span class="math notranslate nohighlight">\(a + c \le b + c\)</span> for every <span class="math notranslate nohighlight">\(a\)</span>, <span class="math notranslate nohighlight">\(b\)</span>, and <span class="math notranslate nohighlight">\(c\)</span> in <span class="math notranslate nohighlight">\(R\)</span>, and <span class="math notranslate nohighlight">\(0 \le a\)</span> and <span class="math notranslate nohighlight">\(0 \le b\)</span> implies <span class="math notranslate nohighlight">\(0 \le a b\)</span> for every <span class="math notranslate nohighlight">\(a\)</span> and <span class="math notranslate nohighlight">\(b\)</span> in <span class="math notranslate nohighlight">\(R\)</span>.</p></li> <li><p>A <em>metric space</em> consists of a set <span class="math notranslate nohighlight">\(X\)</span> and a function <span class="math notranslate nohighlight">\(d : X \times X \to \mathbb{R}\)</span> such that the following hold:</p> <ul class="simple"> <li><p><span class="math notranslate nohighlight">\(d(x, y) \ge 0\)</span> for every <span class="math notranslate nohighlight">\(x\)</span> and <span class="math notranslate nohighlight">\(y\)</span> in <span class="math notranslate nohighlight">\(X\)</span>.</p></li> <li><p><span class="math notranslate nohighlight">\(d(x, y) = 0\)</span> if and only if <span class="math notranslate nohighlight">\(x = y\)</span>.</p></li> <li><p><span class="math notranslate nohighlight">\(d(x, y) = d(y, x)\)</span> for every <span class="math notranslate nohighlight">\(x\)</span> and <span class="math notranslate nohighlight">\(y\)</span> in <span class="math notranslate nohighlight">\(X\)</span>.</p></li> <li><p><span class="math notranslate nohighlight">\(d(x, z) \le d(x, y) + d(y, z)\)</span> for every <span class="math notranslate nohighlight">\(x\)</span>, <span class="math notranslate nohighlight">\(y\)</span>, and <span class="math notranslate nohighlight">\(z\)</span> in <span class="math notranslate nohighlight">\(X\)</span>.</p></li> </ul> </li> <li><p>A <em>topological space</em> consists of a set <span class="math notranslate nohighlight">\(X\)</span> and a collection <span class="math notranslate nohighlight">\(\mathcal T\)</span> of subsets of <span class="math notranslate nohighlight">\(X\)</span>, called the <em>open subsets of</em> <span class="math notranslate nohighlight">\(X\)</span>, such that the following hold:</p> <ul class="simple"> <li><p>The empty set and <span class="math notranslate nohighlight">\(X\)</span> are open.</p></li> <li><p>The intersection of two open sets is open.</p></li> <li><p>An arbitrary union of open sets is open.</p></li> </ul> </li> </ol> <p>In each of these examples, the elements of the structure belong to a set, the <em>carrier set</em>, that sometimes stands proxy for the entire structure. For example, when we say “let <span class="math notranslate nohighlight">\(G\)</span> be a group” and then “let <span class="math notranslate nohighlight">\(g \in G\)</span>,” we are using <span class="math notranslate nohighlight">\(G\)</span> to stand for both the structure and its carrier. Not every algebraic structure is associated with a single carrier set in this way. For example, a <em>bipartite graph</em> involves a relation between two sets, as does a <em>Galois connection</em>, A <em>category</em> also involves two sets of interest, commonly called the <em>objects</em> and the <em>morphisms</em>.</p> <p>The examples indicate some of the things that a proof assistant has to do in order to support algebraic reasoning. First, it needs to recognize concrete instances of structures. The number systems <span class="math notranslate nohighlight">\(\mathbb{Z}\)</span>, <span class="math notranslate nohighlight">\(\mathbb{Q}\)</span>, and <span class="math notranslate nohighlight">\(\mathbb{R}\)</span> are all ordered rings, and we should be able to apply a generic theorem about ordered rings in any of these instances. Sometimes a concrete set may be an instance of a structure in more than one way. For example, in addition to the usual topology on <span class="math notranslate nohighlight">\(\mathbb{R}\)</span>, which forms the basis for real analysis, we can also consider the <em>discrete</em> topology on <span class="math notranslate nohighlight">\(\mathbb{R}\)</span>, in which every set is open.</p> <p>Second, a proof assistant needs to support generic notation on structures. In Lean, the notation <code class="docutils literal notranslate"><span class="pre">*</span></code> is used for multiplication in all the usual number systems, as well as for multiplication in generic groups and rings. When we use an expression like <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span> <span class="pre">*</span> <span class="pre">y</span></code>, Lean has to use information about the types of <code class="docutils literal notranslate"><span class="pre">f</span></code>, <code class="docutils literal notranslate"><span class="pre">x</span></code>, and <code class="docutils literal notranslate"><span class="pre">y</span></code> to determine which multiplication we have in mind.</p> <p>Third, it needs to deal with the fact that structures can inherit definitions, theorems, and notation from other structures in various ways. Some structures extend others by adding more axioms. A commutative ring is still a ring, so any definition that makes sense in a ring also makes sense in a commutative ring, and any theorem that holds in a ring also holds in a commutative ring. Some structures extend others by adding more data. For example, the additive part of any ring is an additive group. The ring structure adds a multiplication and an identity, as well as axioms that govern them and relate them to the additive part. Sometimes we can define one structure in terms of another. Any metric space has a canonical topology associated with it, the <em>metric space topology</em>, and there are various topologies that can be associated with any linear ordering.</p> <p>Finally, it is important to keep in mind that mathematics allows us to use functions and operations to define structures in the same way we use functions and operations to define numbers. Products and powers of groups are again groups. For every <span class="math notranslate nohighlight">\(n\)</span>, the integers modulo <span class="math notranslate nohighlight">\(n\)</span> form a ring, and for every <span class="math notranslate nohighlight">\(k > 0\)</span>, the <span class="math notranslate nohighlight">\(k \times k\)</span> matrices of polynomials with coefficients in that ring again form a ring. Thus we can calculate with structures just as easily as we can calculate with their elements. This means that algebraic structures lead dual lives in mathematics, as containers for collections of objects and as objects in their own right. A proof assistant has to accommodate this dual role.</p> <p>When dealing with elements of a type that has an algebraic structure associated with it, a proof assistant needs to recognize the structure and find the relevant definitions, theorems, and notation. All this should sound like a lot of work, and it is. But Lean uses a small collection of fundamental mechanisms to carry out these tasks. The goal of this section is to explain these mechanisms and show you how to use them.</p> <p>The first ingredient is almost too obvious to mention: formally speaking, algebraic structures are structures in the sense of <a class="reference internal" href="#section-structures"><span class="std std-numref">Section 6.1</span></a>. An algebraic structure is a specification of a bundle of data satisfying some axiomatic hypotheses, and we saw in <a class="reference internal" href="#section-structures"><span class="std std-numref">Section 6.1</span></a> that this is exactly what the <code class="docutils literal notranslate"><span class="pre">structure</span></code> command is designed to accommodate. It’s a marriage made in heaven!</p> <p>Given a data type <code class="docutils literal notranslate"><span class="pre">α</span></code>, we can define the group structure on <code class="docutils literal notranslate"><span class="pre">α</span></code> as follows.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">structure</span> <span class="n">Group₁</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">)</span> <span class="n">where</span> <span class="n">mul</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">α</span> <span class="n">one</span> <span class="o">:</span> <span class="n">α</span> <span class="n">inv</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">α</span> <span class="n">mul_assoc</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">mul</span> <span class="o">(</span><span class="n">mul</span> <span class="n">x</span> <span class="n">y</span><span class="o">)</span> <span class="n">z</span> <span class="bp">=</span> <span class="n">mul</span> <span class="n">x</span> <span class="o">(</span><span class="n">mul</span> <span class="n">y</span> <span class="n">z</span><span class="o">)</span> <span class="n">mul_one</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">mul</span> <span class="n">x</span> <span class="n">one</span> <span class="bp">=</span> <span class="n">x</span> <span class="n">one_mul</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">mul</span> <span class="n">one</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">x</span> <span class="n">mul_left_inv</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">mul</span> <span class="o">(</span><span class="n">inv</span> <span class="n">x</span><span class="o">)</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">one</span> </pre></div> </div> <p>Notice that the type <code class="docutils literal notranslate"><span class="pre">α</span></code> is a <em>parameter</em> in the definition of <code class="docutils literal notranslate"><span class="pre">group₁</span></code>. So you should think of an object <code class="docutils literal notranslate"><span class="pre">struc</span> <span class="pre">:</span> <span class="pre">Group₁</span> <span class="pre">α</span></code> as being a group structure on <code class="docutils literal notranslate"><span class="pre">α</span></code>. We saw in <a class="reference internal" href="C02_Basics.html#proving-identities-in-algebraic-structures"><span class="std std-numref">Section 2.2</span></a> that the counterpart <code class="docutils literal notranslate"><span class="pre">mul_right_inv</span></code> to <code class="docutils literal notranslate"><span class="pre">mul_left_inv</span></code> follows from the other group axioms, so there is no need to add it to the definition.</p> <p>This definition of a group is similar to the definition of <code class="docutils literal notranslate"><span class="pre">Group</span></code> in mathlib, and we have chosen the name <code class="docutils literal notranslate"><span class="pre">Group₁</span></code> to distinguish our version. If you write <code class="docutils literal notranslate"><span class="pre">#check</span> <span class="pre">Group</span></code> and ctrl-click on the definition, you will see that the mathlib version of <code class="docutils literal notranslate"><span class="pre">Group</span></code> is defined to extend another structure; we will explain how to do that later. If you type <code class="docutils literal notranslate"><span class="pre">#print</span> <span class="pre">Group</span></code> you will also see that the mathlib version of <code class="docutils literal notranslate"><span class="pre">Group</span></code> has a number of extra fields. For reasons we will explain later, sometimes it is useful to add redundant information to a structure, so that there are additional fields for objects and functions that can be defined from the core data. Don’t worry about that for now. Rest assured that our simplified version <code class="docutils literal notranslate"><span class="pre">Group₁</span></code> is morally the same as the definition of a group that mathlib uses.</p> <p>It is sometimes useful to bundle the type together with the structure, and mathlib also contains a definition of a <code class="docutils literal notranslate"><span class="pre">GroupCat</span></code> structure that is equivalent to the following:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">structure</span> <span class="n">Group₁Cat</span> <span class="n">where</span> <span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span> <span class="n">str</span> <span class="o">:</span> <span class="n">Group₁</span> <span class="n">α</span> </pre></div> </div> <p>The mathlib version is found in <code class="docutils literal notranslate"><span class="pre">Algebra.Category.Group.Basic</span></code>, and you can <code class="docutils literal notranslate"><span class="pre">#check</span></code> it if you add this to the imports at the beginning of the examples file.</p> <p>For reasons that will become clearer below, it is more often useful to keep the type <code class="docutils literal notranslate"><span class="pre">α</span></code> separate from the structure <code class="docutils literal notranslate"><span class="pre">Group</span> <span class="pre">α</span></code>. We refer to the two objects together as a <em>partially bundled structure</em>, since the representation combines most, but not all, of the components into one structure. It is common in mathlib to use capital roman letters like <code class="docutils literal notranslate"><span class="pre">G</span></code> for a type when it is used as the carrier type for a group.</p> <p>Let’s construct a group, which is to say, an element of the <code class="docutils literal notranslate"><span class="pre">Group₁</span></code> type. For any pair of types <code class="docutils literal notranslate"><span class="pre">α</span></code> and <code class="docutils literal notranslate"><span class="pre">β</span></code>, Mathlib defines the type <code class="docutils literal notranslate"><span class="pre">Equiv</span> <span class="pre">α</span> <span class="pre">β</span></code> of <em>equivalences</em> between <code class="docutils literal notranslate"><span class="pre">α</span></code> and <code class="docutils literal notranslate"><span class="pre">β</span></code>. Mathlib also defines the suggestive notation <code class="docutils literal notranslate"><span class="pre">α</span> <span class="pre">≃</span> <span class="pre">β</span></code> for this type. An element <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">α</span> <span class="pre">≃</span> <span class="pre">β</span></code> is a bijection between <code class="docutils literal notranslate"><span class="pre">α</span></code> and <code class="docutils literal notranslate"><span class="pre">β</span></code> represented by four components: a function <code class="docutils literal notranslate"><span class="pre">f.toFun</span></code> from <code class="docutils literal notranslate"><span class="pre">α</span></code> to <code class="docutils literal notranslate"><span class="pre">β</span></code>, the inverse function <code class="docutils literal notranslate"><span class="pre">f.invFun</span></code> from <code class="docutils literal notranslate"><span class="pre">β</span></code> to <code class="docutils literal notranslate"><span class="pre">α</span></code>, and two properties that specify these functions are indeed inverse to one another.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">(</span><span class="n">α</span> <span class="n">β</span> <span class="n">γ</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">)</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">≃</span> <span class="n">β</span><span class="o">)</span> <span class="o">(</span><span class="n">g</span> <span class="o">:</span> <span class="n">β</span> <span class="bp">≃</span> <span class="n">γ</span><span class="o">)</span> <span class="k">#check</span> <span class="n">Equiv</span> <span class="n">α</span> <span class="n">β</span> <span class="k">#check</span> <span class="o">(</span><span class="n">f.toFun</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">β</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">f.invFun</span> <span class="o">:</span> <span class="n">β</span> <span class="bp">→</span> <span class="n">α</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">f.right_inv</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="o">:</span> <span class="n">β</span><span class="o">,</span> <span class="n">f</span> <span class="o">(</span><span class="n">f.invFun</span> <span class="n">x</span><span class="o">)</span> <span class="bp">=</span> <span class="n">x</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">f.left_inv</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">f.invFun</span> <span class="o">(</span><span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="bp">=</span> <span class="n">x</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">Equiv.refl</span> <span class="n">α</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">≃</span> <span class="n">α</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">f.symm</span> <span class="o">:</span> <span class="n">β</span> <span class="bp">≃</span> <span class="n">α</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">f.trans</span> <span class="n">g</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">≃</span> <span class="n">γ</span><span class="o">)</span> </pre></div> </div> <p>Notice the creative naming of the last three constructions. We think of the identity function <code class="docutils literal notranslate"><span class="pre">Equiv.refl</span></code>, the inverse operation <code class="docutils literal notranslate"><span class="pre">Equiv.symm</span></code>, and the composition operation <code class="docutils literal notranslate"><span class="pre">Equiv.trans</span></code> as explicit evidence that the property of being in bijective correspondence is an equivalence relation.</p> <p>Notice also that <code class="docutils literal notranslate"><span class="pre">f.trans</span> <span class="pre">g</span></code> requires composing the forward functions in reverse order. Mathlib has declared a <em>coercion</em> from <code class="docutils literal notranslate"><span class="pre">Equiv</span> <span class="pre">α</span> <span class="pre">β</span></code> to the function type <code class="docutils literal notranslate"><span class="pre">α</span> <span class="pre">→</span> <span class="pre">β</span></code>, so we can omit writing <code class="docutils literal notranslate"><span class="pre">.toFun</span></code> and have Lean insert it for us.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">f.trans</span> <span class="n">g</span><span class="o">)</span><span class="bp">.</span><span class="n">toFun</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">g.toFun</span> <span class="o">(</span><span class="n">f.toFun</span> <span class="n">x</span><span class="o">)</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">f.trans</span> <span class="n">g</span><span class="o">)</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">g</span> <span class="o">(</span><span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">(</span><span class="n">f.trans</span> <span class="n">g</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">γ</span><span class="o">)</span> <span class="bp">=</span> <span class="n">g</span> <span class="bp">∘</span> <span class="n">f</span> <span class="o">:=</span> <span class="n">rfl</span> </pre></div> </div> <p>Mathlib also defines the type <code class="docutils literal notranslate"><span class="pre">perm</span> <span class="pre">α</span></code> of equivalences between <code class="docutils literal notranslate"><span class="pre">α</span></code> and itself.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">)</span> <span class="o">:</span> <span class="n">Equiv.Perm</span> <span class="n">α</span> <span class="bp">=</span> <span class="o">(</span><span class="n">α</span> <span class="bp">≃</span> <span class="n">α</span><span class="o">)</span> <span class="o">:=</span> <span class="n">rfl</span> </pre></div> </div> <p>It should be clear that <code class="docutils literal notranslate"><span class="pre">Equiv.Perm</span> <span class="pre">α</span></code> forms a group under composition of equivalences. We orient things so that <code class="docutils literal notranslate"><span class="pre">mul</span> <span class="pre">f</span> <span class="pre">g</span></code> is equal to <code class="docutils literal notranslate"><span class="pre">g.trans</span> <span class="pre">f</span></code>, whose forward function is <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">∘</span> <span class="pre">g</span></code>. In other words, multiplication is what we ordinarily think of as composition of the bijections. Here we define this group:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">permGroup</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">:</span> <span class="n">Group₁</span> <span class="o">(</span><span class="n">Equiv.Perm</span> <span class="n">α</span><span class="o">)</span> <span class="n">where</span> <span class="n">mul</span> <span class="n">f</span> <span class="n">g</span> <span class="o">:=</span> <span class="n">Equiv.trans</span> <span class="n">g</span> <span class="n">f</span> <span class="n">one</span> <span class="o">:=</span> <span class="n">Equiv.refl</span> <span class="n">α</span> <span class="n">inv</span> <span class="o">:=</span> <span class="n">Equiv.symm</span> <span class="n">mul_assoc</span> <span class="n">f</span> <span class="n">g</span> <span class="n">h</span> <span class="o">:=</span> <span class="o">(</span><span class="n">Equiv.trans_assoc</span> <span class="n">_</span> <span class="n">_</span> <span class="n">_</span><span class="o">)</span><span class="bp">.</span><span class="n">symm</span> <span class="n">one_mul</span> <span class="o">:=</span> <span class="n">Equiv.trans_refl</span> <span class="n">mul_one</span> <span class="o">:=</span> <span class="n">Equiv.refl_trans</span> <span class="n">mul_left_inv</span> <span class="o">:=</span> <span class="n">Equiv.self_trans_symm</span> </pre></div> </div> <p>In fact, mathlib defines exactly this <code class="docutils literal notranslate"><span class="pre">Group</span></code> structure on <code class="docutils literal notranslate"><span class="pre">Equiv.Perm</span> <span class="pre">α</span></code> in the file <code class="docutils literal notranslate"><span class="pre">GroupTheory.Perm.Basic</span></code>. As always, you can hover over the theorems used in the definition of <code class="docutils literal notranslate"><span class="pre">permGroup</span></code> to see their statements, and you can jump to their definitions in the original file to learn more about how they are implemented.</p> <p>In ordinary mathematics, we generally think of notation as independent of structure. For example, we can consider groups <span class="math notranslate nohighlight">\((G_1, \cdot, 1, \cdot^{-1})\)</span>, <span class="math notranslate nohighlight">\((G_2, \circ, e, i(\cdot))\)</span>, and <span class="math notranslate nohighlight">\((G_3, +, 0, -)\)</span>. In the first case, we write the binary operation as <span class="math notranslate nohighlight">\(\cdot\)</span>, the identity at <span class="math notranslate nohighlight">\(1\)</span>, and the inverse function as <span class="math notranslate nohighlight">\(x \mapsto x^{-1}\)</span>. In the second and third cases, we use the notational alternatives shown. When we formalize the notion of a group in Lean, however, the notation is more tightly linked to the structure. In Lean, the components of any <code class="docutils literal notranslate"><span class="pre">Group</span></code> are named <code class="docutils literal notranslate"><span class="pre">mul</span></code>, <code class="docutils literal notranslate"><span class="pre">one</span></code>, and <code class="docutils literal notranslate"><span class="pre">inv</span></code>, and in a moment we will see how multiplicative notation is set up to refer to them. If we want to use additive notation, we instead use an isomorphic structure <code class="docutils literal notranslate"><span class="pre">AdditiveGroup</span></code>. Its components are named <code class="docutils literal notranslate"><span class="pre">add</span></code>, <code class="docutils literal notranslate"><span class="pre">zero</span></code>, and <code class="docutils literal notranslate"><span class="pre">neg</span></code>, and the associated notation is what you would expect it to be.</p> <p>Recall the type <code class="docutils literal notranslate"><span class="pre">Point</span></code> that we defined in <a class="reference internal" href="#section-structures"><span class="std std-numref">Section 6.1</span></a>, and the addition function that we defined there. These definitions are reproduced in the examples file that accompanies this section. As an exercise, define an <code class="docutils literal notranslate"><span class="pre">AddGroup₁</span></code> structure that is similar to the <code class="docutils literal notranslate"><span class="pre">Group₁</span></code> structure we defined above, except that it uses the additive naming scheme just described. Define negation and a zero on the <code class="docutils literal notranslate"><span class="pre">Point</span></code> data type, and define the <code class="docutils literal notranslate"><span class="pre">AddGroup₁</span></code> structure on <code class="docutils literal notranslate"><span class="pre">Point</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">structure</span> <span class="n">AddGroup₁</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">)</span> <span class="n">where</span> <span class="o">(</span><span class="n">add</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">α</span><span class="o">)</span> <span class="c1">-- fill in the rest</span> <span class="kd">@[ext]</span> <span class="kd">structure</span> <span class="n">Point</span> <span class="n">where</span> <span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="n">y</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="n">z</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="kn">namespace</span> <span class="n">Point</span> <span class="kd">def</span> <span class="n">add</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">Point</span><span class="o">)</span> <span class="o">:</span> <span class="n">Point</span> <span class="o">:=</span> <span class="o">⟨</span><span class="n">a.x</span> <span class="bp">+</span> <span class="n">b.x</span><span class="o">,</span> <span class="n">a.y</span> <span class="bp">+</span> <span class="n">b.y</span><span class="o">,</span> <span class="n">a.z</span> <span class="bp">+</span> <span class="n">b.z</span><span class="o">⟩</span> <span class="kd">def</span> <span class="n">neg</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">Point</span><span class="o">)</span> <span class="o">:</span> <span class="n">Point</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="kd">def</span> <span class="n">zero</span> <span class="o">:</span> <span class="n">Point</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="kd">def</span> <span class="n">addGroupPoint</span> <span class="o">:</span> <span class="n">AddGroup₁</span> <span class="n">Point</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="kd">end</span> <span class="n">Point</span> </pre></div> </div> <p>We are making progress. Now we know how to define algebraic structures in Lean, and we know how to define instances of those structures. But we also want to associate notation with structures so that we can use it with each instance. Moreover, we want to arrange it so that we can define an operation on a structure and use it with any particular instance, and we want to arrange it so that we can prove a theorem about a structure and use it with any instance.</p> <p>In fact, mathlib is already set up to use generic group notation, definitions, and theorems for <code class="docutils literal notranslate"><span class="pre">Equiv.Perm</span> <span class="pre">α</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">(</span><span class="n">f</span> <span class="n">g</span> <span class="o">:</span> <span class="n">Equiv.Perm</span> <span class="n">α</span><span class="o">)</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="k">#check</span> <span class="n">f</span> <span class="bp">*</span> <span class="n">g</span> <span class="k">#check</span> <span class="n">mul_assoc</span> <span class="n">f</span> <span class="n">g</span> <span class="n">g</span><span class="bp">⁻¹</span> <span class="c1">-- group power, defined for any group</span> <span class="k">#check</span> <span class="n">g</span> <span class="bp">^</span> <span class="n">n</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">*</span> <span class="n">g</span> <span class="bp">*</span> <span class="n">g</span><span class="bp">⁻¹</span> <span class="bp">=</span> <span class="n">f</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mul_assoc</span><span class="o">,</span> <span class="n">mul_right_inv</span><span class="o">,</span> <span class="n">mul_one</span><span class="o">]</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">*</span> <span class="n">g</span> <span class="bp">*</span> <span class="n">g</span><span class="bp">⁻¹</span> <span class="bp">=</span> <span class="n">f</span> <span class="o">:=</span> <span class="n">mul_inv_cancel_right</span> <span class="n">f</span> <span class="n">g</span> <span class="kd">example</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">(</span><span class="n">f</span> <span class="n">g</span> <span class="o">:</span> <span class="n">Equiv.Perm</span> <span class="n">α</span><span class="o">)</span> <span class="o">:</span> <span class="n">g.symm.trans</span> <span class="o">(</span><span class="n">g.trans</span> <span class="n">f</span><span class="o">)</span> <span class="bp">=</span> <span class="n">f</span> <span class="o">:=</span> <span class="n">mul_inv_cancel_right</span> <span class="n">f</span> <span class="n">g</span> </pre></div> </div> <p>You can check that this is not the case for the additive group structure on <code class="docutils literal notranslate"><span class="pre">Point</span></code> that we asked you to define above. Our task now is to understand that magic that goes on under the hood in order to make the examples for <code class="docutils literal notranslate"><span class="pre">Equiv.Perm</span> <span class="pre">α</span></code> work the way they do.</p> <p>The issue is that Lean needs to be able to <em>find</em> the relevant notation and the implicit group structure, using the information that is found in the expressions that we type. Similarly, when we write <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">+</span> <span class="pre">y</span></code> with expressions <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code> that have type <code class="docutils literal notranslate"><span class="pre">ℝ</span></code>, Lean needs to interpret the <code class="docutils literal notranslate"><span class="pre">+</span></code> symbol as the relevant addition function on the reals. It also has to recognize the type <code class="docutils literal notranslate"><span class="pre">ℝ</span></code> as an instance of a commutative ring, so that all the definitions and theorems for a commutative ring are available. For another example, continuity is defined in Lean relative to any two topological spaces. When we have <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">ℝ</span> <span class="pre">→</span> <span class="pre">ℂ</span></code> and we write <code class="docutils literal notranslate"><span class="pre">Continuous</span> <span class="pre">f</span></code>, Lean has to find the relevant topologies on <code class="docutils literal notranslate"><span class="pre">ℝ</span></code> and <code class="docutils literal notranslate"><span class="pre">ℂ</span></code>.</p> <p>The magic is achieved with a combination of three things.</p> <ol class="arabic simple"> <li><p><em>Logic.</em> A definition that should be interpreted in any group takes, as arguments, the type of the group and the group structure as arguments. Similarly, a theorem about the elements of an arbitrary group begins with universal quantifiers over the type of the group and the group structure.</p></li> <li><p><em>Implicit arguments.</em> The arguments for the type and the structure are generally left implicit, so that we do not have to write them or see them in the Lean information window. Lean fills the information in for us silently.</p></li> <li><p><em>Type class inference.</em> Also known as <em>class inference</em>, this is a simple but powerful mechanism that enables us to register information for Lean to use later on. When Lean is called on to fill in implicit arguments to a definition, theorem, or piece of notation, it can make use of information that has been registered.</p></li> </ol> <p>Whereas an annotation <code class="docutils literal notranslate"><span class="pre">(grp</span> <span class="pre">:</span> <span class="pre">Group</span> <span class="pre">G)</span></code> tells Lean that it should expect to be given that argument explicitly and the annotation <code class="docutils literal notranslate"><span class="pre">{grp</span> <span class="pre">:</span> <span class="pre">Group</span> <span class="pre">G}</span></code> tells Lean that it should try to figure it out from contextual cues in the expression, the annotation <code class="docutils literal notranslate"><span class="pre">[grp</span> <span class="pre">:</span> <span class="pre">Group</span> <span class="pre">G]</span></code> tells Lean that the corresponding argument should be synthesized using type class inference. Since the whole point to the use of such arguments is that we generally do not need to refer to them explicitly, Lean allows us to write <code class="docutils literal notranslate"><span class="pre">[Group</span> <span class="pre">G]</span></code> and leave the name anonymous. You have probably already noticed that Lean chooses names like <code class="docutils literal notranslate"><span class="pre">_inst_1</span></code> automatically. When we use the anonymous square-bracket annotation with the <code class="docutils literal notranslate"><span class="pre">variables</span></code> command, then as long as the variables are still in scope, Lean automatically adds the argument <code class="docutils literal notranslate"><span class="pre">[Group</span> <span class="pre">G]</span></code> to any definition or theorem that mentions <code class="docutils literal notranslate"><span class="pre">G</span></code>.</p> <p>How do we register the information that Lean needs to use to carry out the search? Returning to our group example, we need only make two changes. First, instead of using the <code class="docutils literal notranslate"><span class="pre">structure</span></code> command to define the group structure, we use the keyword <code class="docutils literal notranslate"><span class="pre">class</span></code> to indicate that it is a candidate for class inference. Second, instead of defining particular instances with <code class="docutils literal notranslate"><span class="pre">def</span></code>, we use the keyword <code class="docutils literal notranslate"><span class="pre">instance</span></code> to register the particular instance with Lean. As with the names of class variables, we are allowed to leave the name of an instance definition anonymous, since in general we intend Lean to find it and put it to use without troubling us with the details.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">Group₂</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">)</span> <span class="n">where</span> <span class="n">mul</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">α</span> <span class="n">one</span> <span class="o">:</span> <span class="n">α</span> <span class="n">inv</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">α</span> <span class="n">mul_assoc</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">mul</span> <span class="o">(</span><span class="n">mul</span> <span class="n">x</span> <span class="n">y</span><span class="o">)</span> <span class="n">z</span> <span class="bp">=</span> <span class="n">mul</span> <span class="n">x</span> <span class="o">(</span><span class="n">mul</span> <span class="n">y</span> <span class="n">z</span><span class="o">)</span> <span class="n">mul_one</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">mul</span> <span class="n">x</span> <span class="n">one</span> <span class="bp">=</span> <span class="n">x</span> <span class="n">one_mul</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">mul</span> <span class="n">one</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">x</span> <span class="n">mul_left_inv</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">mul</span> <span class="o">(</span><span class="n">inv</span> <span class="n">x</span><span class="o">)</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">one</span> <span class="kd">instance</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">:</span> <span class="n">Group₂</span> <span class="o">(</span><span class="n">Equiv.Perm</span> <span class="n">α</span><span class="o">)</span> <span class="n">where</span> <span class="n">mul</span> <span class="n">f</span> <span class="n">g</span> <span class="o">:=</span> <span class="n">Equiv.trans</span> <span class="n">g</span> <span class="n">f</span> <span class="n">one</span> <span class="o">:=</span> <span class="n">Equiv.refl</span> <span class="n">α</span> <span class="n">inv</span> <span class="o">:=</span> <span class="n">Equiv.symm</span> <span class="n">mul_assoc</span> <span class="n">f</span> <span class="n">g</span> <span class="n">h</span> <span class="o">:=</span> <span class="o">(</span><span class="n">Equiv.trans_assoc</span> <span class="n">_</span> <span class="n">_</span> <span class="n">_</span><span class="o">)</span><span class="bp">.</span><span class="n">symm</span> <span class="n">one_mul</span> <span class="o">:=</span> <span class="n">Equiv.trans_refl</span> <span class="n">mul_one</span> <span class="o">:=</span> <span class="n">Equiv.refl_trans</span> <span class="n">mul_left_inv</span> <span class="o">:=</span> <span class="n">Equiv.self_trans_symm</span> </pre></div> </div> <p>The following illustrates their use.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="bp">@</span><span class="n">Group₂.mul</span> <span class="kd">def</span> <span class="n">mySquare</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">Group₂</span> <span class="n">α</span><span class="o">]</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="o">:=</span> <span class="n">Group₂.mul</span> <span class="n">x</span> <span class="n">x</span> <span class="k">#check</span> <span class="bp">@</span><span class="n">mySquare</span> <span class="kn">section</span> <span class="kd">variable</span> <span class="o">{</span><span class="n">β</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">(</span><span class="n">f</span> <span class="n">g</span> <span class="o">:</span> <span class="n">Equiv.Perm</span> <span class="n">β</span><span class="o">)</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">Group₂.mul</span> <span class="n">f</span> <span class="n">g</span> <span class="bp">=</span> <span class="n">g.trans</span> <span class="n">f</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">mySquare</span> <span class="n">f</span> <span class="bp">=</span> <span class="n">f.trans</span> <span class="n">f</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">end</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">#check</span></code> command shows that <code class="docutils literal notranslate"><span class="pre">Group₂.mul</span></code> has an implicit argument <code class="docutils literal notranslate"><span class="pre">[Group₂</span> <span class="pre">α]</span></code> that we expect to be found by class inference, where <code class="docutils literal notranslate"><span class="pre">α</span></code> is the type of the arguments to <code class="docutils literal notranslate"><span class="pre">Group₂.mul</span></code>. In other words, <code class="docutils literal notranslate"><span class="pre">{α</span> <span class="pre">:</span> <span class="pre">Type*}</span></code> is the implicit argument for the type of the group elements and <code class="docutils literal notranslate"><span class="pre">[Group₂</span> <span class="pre">α]</span></code> is the implicit argument for the group structure on <code class="docutils literal notranslate"><span class="pre">α</span></code>. Similarly, when we define a generic squaring function <code class="docutils literal notranslate"><span class="pre">my_square</span></code> for <code class="docutils literal notranslate"><span class="pre">Group₂</span></code>, we use an implicit argument <code class="docutils literal notranslate"><span class="pre">{α</span> <span class="pre">:</span> <span class="pre">Type*}</span></code> for the type of the elements and an implicit argument <code class="docutils literal notranslate"><span class="pre">[Group₂</span> <span class="pre">α]</span></code> for the <code class="docutils literal notranslate"><span class="pre">Group₂</span></code> structure.</p> <p>In the first example, when we write <code class="docutils literal notranslate"><span class="pre">Group₂.mul</span> <span class="pre">f</span> <span class="pre">g</span></code>, the type of <code class="docutils literal notranslate"><span class="pre">f</span></code> and <code class="docutils literal notranslate"><span class="pre">g</span></code> tells Lean that in the argument <code class="docutils literal notranslate"><span class="pre">α</span></code> to <code class="docutils literal notranslate"><span class="pre">Group₂.mul</span></code> has to be instantiated to <code class="docutils literal notranslate"><span class="pre">Equiv.Perm</span> <span class="pre">β</span></code>. That means that Lean has to find an element of <code class="docutils literal notranslate"><span class="pre">Group₂</span> <span class="pre">(Equiv.Perm</span> <span class="pre">β)</span></code>. The previous <code class="docutils literal notranslate"><span class="pre">instance</span></code> declaration tells Lean exactly how to do that. Problem solved!</p> <p>This simple mechanism for registering information so that Lean can find it when it needs it is remarkably useful. Here is one way it comes up. In Lean’s foundation, a data type <code class="docutils literal notranslate"><span class="pre">α</span></code> may be empty. In a number of applications, however, it is useful to know that a type has at least one element. For example, the function <code class="docutils literal notranslate"><span class="pre">List.head</span></code>, which returns the first element of a list, can return the default value when the list is empty. To make that work, the Lean library defines a class <code class="docutils literal notranslate"><span class="pre">Inhabited</span> <span class="pre">α</span></code>, which does nothing more than store a default value. We can show that the <code class="docutils literal notranslate"><span class="pre">Point</span></code> type is an instance:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="o">:</span> <span class="n">Inhabited</span> <span class="n">Point</span> <span class="n">where</span> <span class="n">default</span> <span class="o">:=</span> <span class="o">⟨</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">⟩</span> <span class="k">#check</span> <span class="o">(</span><span class="n">default</span> <span class="o">:</span> <span class="n">Point</span><span class="o">)</span> <span class="kd">example</span> <span class="o">:</span> <span class="o">([]</span> <span class="o">:</span> <span class="n">List</span> <span class="n">Point</span><span class="o">)</span><span class="bp">.</span><span class="n">headI</span> <span class="bp">=</span> <span class="n">default</span> <span class="o">:=</span> <span class="n">rfl</span> </pre></div> </div> <p>The class inference mechanism is also used for generic notation. The expression <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">+</span> <span class="pre">y</span></code> is an abbreviation for <code class="docutils literal notranslate"><span class="pre">Add.add</span> <span class="pre">x</span> <span class="pre">y</span></code> where—you guessed it—<code class="docutils literal notranslate"><span class="pre">Add</span> <span class="pre">α</span></code> is a class that stores a binary function on <code class="docutils literal notranslate"><span class="pre">α</span></code>. Writing <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">+</span> <span class="pre">y</span></code> tells Lean to find a registered instance of <code class="docutils literal notranslate"><span class="pre">[Add.add</span> <span class="pre">α]</span></code> and use the corresponding function. Below, we register the addition function for <code class="docutils literal notranslate"><span class="pre">Point</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="o">:</span> <span class="n">Add</span> <span class="n">Point</span> <span class="n">where</span> <span class="n">add</span> <span class="o">:=</span> <span class="n">Point.add</span> <span class="kn">section</span> <span class="kd">variable</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">Point</span><span class="o">)</span> <span class="k">#check</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">y</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">y</span> <span class="bp">=</span> <span class="n">Point.add</span> <span class="n">x</span> <span class="n">y</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">end</span> </pre></div> </div> <p>In this way, we can assign the notation <code class="docutils literal notranslate"><span class="pre">+</span></code> to binary operations on other types as well.</p> <p>But we can do even better. We have seen that <code class="docutils literal notranslate"><span class="pre">*</span></code> can be used in any group, <code class="docutils literal notranslate"><span class="pre">+</span></code> can be used in any additive group, and both can be used in any ring. When we define a new instance of a ring in Lean, we don’t have to define <code class="docutils literal notranslate"><span class="pre">+</span></code> and <code class="docutils literal notranslate"><span class="pre">*</span></code> for that instance, because Lean knows that these are defined for every ring. We can use this method to specify notation for our <code class="docutils literal notranslate"><span class="pre">Group₂</span></code> class:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="n">hasMulGroup₂</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">Group₂</span> <span class="n">α</span><span class="o">]</span> <span class="o">:</span> <span class="n">Mul</span> <span class="n">α</span> <span class="o">:=</span> <span class="o">⟨</span><span class="n">Group₂.mul</span><span class="o">⟩</span> <span class="kd">instance</span> <span class="n">hasOneGroup₂</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">Group₂</span> <span class="n">α</span><span class="o">]</span> <span class="o">:</span> <span class="n">One</span> <span class="n">α</span> <span class="o">:=</span> <span class="o">⟨</span><span class="n">Group₂.one</span><span class="o">⟩</span> <span class="kd">instance</span> <span class="n">hasInvGroup₂</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">Group₂</span> <span class="n">α</span><span class="o">]</span> <span class="o">:</span> <span class="n">Inv</span> <span class="n">α</span> <span class="o">:=</span> <span class="o">⟨</span><span class="n">Group₂.inv</span><span class="o">⟩</span> <span class="kn">section</span> <span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">(</span><span class="n">f</span> <span class="n">g</span> <span class="o">:</span> <span class="n">Equiv.Perm</span> <span class="n">α</span><span class="o">)</span> <span class="k">#check</span> <span class="n">f</span> <span class="bp">*</span> <span class="mi">1</span> <span class="bp">*</span> <span class="n">g</span><span class="bp">⁻¹</span> <span class="kd">def</span> <span class="n">foo</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">*</span> <span class="mi">1</span> <span class="bp">*</span> <span class="n">g</span><span class="bp">⁻¹</span> <span class="bp">=</span> <span class="n">g.symm.trans</span> <span class="o">((</span><span class="n">Equiv.refl</span> <span class="n">α</span><span class="o">)</span><span class="bp">.</span><span class="n">trans</span> <span class="n">f</span><span class="o">)</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">end</span> </pre></div> </div> <p>In this case, we have to supply names for the instances, because Lean has a hard time coming up with good defaults. What makes this approach work is that Lean carries out a recursive search. According to the instances we have declared, Lean can find an instance of <code class="docutils literal notranslate"><span class="pre">Mul</span> <span class="pre">(Equiv.Perm</span> <span class="pre">α)</span></code> by finding an instance of <code class="docutils literal notranslate"><span class="pre">Group₂</span> <span class="pre">(Equiv.Perm</span> <span class="pre">α)</span></code>, and it can find an instance of <code class="docutils literal notranslate"><span class="pre">Group₂</span> <span class="pre">(Equiv.Perm</span> <span class="pre">α)</span></code> because we have provided one. Lean is capable of finding these two facts and chaining them together.</p> <p>The example we have just given is dangerous, because Lean’s library also has an instance of <code class="docutils literal notranslate"><span class="pre">Group</span> <span class="pre">(Equiv.Perm</span> <span class="pre">α)</span></code>, and multiplication is defined on any group. So it is ambiguous as to which instance is found. In fact, Lean favors more recent declarations unless you explicitly specify a different priority. Also, there is another way to tell Lean that one structure is an instance of another, using the <code class="docutils literal notranslate"><span class="pre">extends</span></code> keyword. This is how <code class="docutils literal notranslate"><span class="pre">mathlib</span></code> specifies that, for example, every commutative ring is a ring. You can find more information in a <a class="reference external" href="https://leanprover.github.io/theorem_proving_in_lean4/type_classes.html#managing-type-class-inference">section on class inference</a> in <em>Theorem Proving in Lean</em>.</p> <p>In general, it is a bad idea to specify a value of <code class="docutils literal notranslate"><span class="pre">*</span></code> for an instance of an algebraic structure that already has the notation defined. Redefining the notion of <code class="docutils literal notranslate"><span class="pre">Group</span></code> in Lean is an artificial example. In this case, however, both interpretations of the group notation unfold to <code class="docutils literal notranslate"><span class="pre">Equiv.trans</span></code>, <code class="docutils literal notranslate"><span class="pre">Equiv.refl</span></code>, and <code class="docutils literal notranslate"><span class="pre">Equiv.symm</span></code>, in the same way.</p> <p>As a similarly artificial exercise, define a class <code class="docutils literal notranslate"><span class="pre">AddGroup₂</span></code> in analogy to <code class="docutils literal notranslate"><span class="pre">Group₂</span></code>. Define the usual notation for addition, negation, and zero on any <code class="docutils literal notranslate"><span class="pre">AddGroup₂</span></code> using the classes <code class="docutils literal notranslate"><span class="pre">Add</span></code>, <code class="docutils literal notranslate"><span class="pre">Neg</span></code>, and <code class="docutils literal notranslate"><span class="pre">Zero</span></code>. Then show <code class="docutils literal notranslate"><span class="pre">Point</span></code> is an instance of <code class="docutils literal notranslate"><span class="pre">AddGroup₂</span></code>. Try it out and make sure that the additive group notation works for elements of <code class="docutils literal notranslate"><span class="pre">Point</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">AddGroup₂</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">)</span> <span class="n">where</span> <span class="n">add</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">α</span> <span class="c1">-- fill in the rest</span> </pre></div> </div> <p>It is not a big problem that we have already declared instances <code class="docutils literal notranslate"><span class="pre">Add</span></code>, <code class="docutils literal notranslate"><span class="pre">Neg</span></code>, and <code class="docutils literal notranslate"><span class="pre">Zero</span></code> for <code class="docutils literal notranslate"><span class="pre">Point</span></code> above. Once again, the two ways of synthesizing the notation should come up with the same answer.</p> <p>Class inference is subtle, and you have to be careful when using it, because it configures automation that invisibly governs the interpretation of the expressions we type. When used wisely, however, class inference is a powerful tool. It is what makes algebraic reasoning possible in Lean.</p> </section> <section id="building-the-gaussian-integers"> <span id="section-building-the-gaussian-integers"></span><h2><span class="section-number">6.3. </span>Building the Gaussian Integers<a class="headerlink" href="#building-the-gaussian-integers" title="Permalink to this heading"></a></h2> <p>We will now illustrate the use of the algebraic hierarchy in Lean by building an important mathematical object, the <em>Gaussian integers</em>, and showing that it is a Euclidean domain. In other words, according to the terminology we have been using, we will define the Gaussian integers and show that they are an instance of the Euclidean domain structure.</p> <p>In ordinary mathematical terms, the set of Gaussian integers <span class="math notranslate nohighlight">\(\Bbb{Z}[i]\)</span> is the set of complex numbers <span class="math notranslate nohighlight">\(\{ a + b i \mid a, b \in \Bbb{Z}\}\)</span>. But rather than define them as a subset of the complex numbers, our goal here is to define them as a data type in their own right. We do this by representing a Gaussian integer as a pair of integers, which we think of as the <em>real</em> and <em>imaginary</em> parts.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">@[ext]</span> <span class="kd">structure</span> <span class="n">gaussInt</span> <span class="n">where</span> <span class="n">re</span> <span class="o">:</span> <span class="n">ℤ</span> <span class="n">im</span> <span class="o">:</span> <span class="n">ℤ</span> </pre></div> </div> <p>We first show that the Gaussian integers have the structure of a ring, with <code class="docutils literal notranslate"><span class="pre">0</span></code> defined to be <code class="docutils literal notranslate"><span class="pre">⟨0,</span> <span class="pre">0⟩</span></code>, <code class="docutils literal notranslate"><span class="pre">1</span></code> defined to be <code class="docutils literal notranslate"><span class="pre">⟨1,</span> <span class="pre">0⟩</span></code>, and addition defined pointwise. To work out the definition of multiplication, remember that we want the element <span class="math notranslate nohighlight">\(i\)</span>, represented by <code class="docutils literal notranslate"><span class="pre">⟨0,</span> <span class="pre">1⟩</span></code>, to be a square root of <span class="math notranslate nohighlight">\(-1\)</span>. Thus we want</p> <div class="math notranslate nohighlight"> \[\begin{split}(a + bi) (c + di) & = ac + bci + adi + bd i^2 \\ & = (ac - bd) + (bc + ad)i.\end{split}\]</div> <p>This explains the definition of <code class="docutils literal notranslate"><span class="pre">hasMul</span></code> below.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="o">:</span> <span class="n">Zero</span> <span class="n">gaussInt</span> <span class="o">:=</span> <span class="o">⟨⟨</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">⟩⟩</span> <span class="kd">instance</span> <span class="o">:</span> <span class="n">One</span> <span class="n">gaussInt</span> <span class="o">:=</span> <span class="o">⟨⟨</span><span class="mi">1</span><span class="o">,</span> <span class="mi">0</span><span class="o">⟩⟩</span> <span class="kd">instance</span> <span class="o">:</span> <span class="n">Add</span> <span class="n">gaussInt</span> <span class="o">:=</span> <span class="o">⟨</span><span class="k">fun</span> <span class="n">x</span> <span class="n">y</span> <span class="bp">=></span> <span class="o">⟨</span><span class="n">x.re</span> <span class="bp">+</span> <span class="n">y.re</span><span class="o">,</span> <span class="n">x.im</span> <span class="bp">+</span> <span class="n">y.im</span><span class="o">⟩⟩</span> <span class="kd">instance</span> <span class="o">:</span> <span class="n">Neg</span> <span class="n">gaussInt</span> <span class="o">:=</span> <span class="o">⟨</span><span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="o">⟨</span><span class="bp">-</span><span class="n">x.re</span><span class="o">,</span> <span class="bp">-</span><span class="n">x.im</span><span class="o">⟩⟩</span> <span class="kd">instance</span> <span class="o">:</span> <span class="n">Mul</span> <span class="n">gaussInt</span> <span class="o">:=</span> <span class="o">⟨</span><span class="k">fun</span> <span class="n">x</span> <span class="n">y</span> <span class="bp">=></span> <span class="o">⟨</span><span class="n">x.re</span> <span class="bp">*</span> <span class="n">y.re</span> <span class="bp">-</span> <span class="n">x.im</span> <span class="bp">*</span> <span class="n">y.im</span><span class="o">,</span> <span class="n">x.re</span> <span class="bp">*</span> <span class="n">y.im</span> <span class="bp">+</span> <span class="n">x.im</span> <span class="bp">*</span> <span class="n">y.re</span><span class="o">⟩⟩</span> </pre></div> </div> <p>As noted in <a class="reference internal" href="#section-structures"><span class="std std-numref">Section 6.1</span></a>, it is a good idea to put all the definitions related to a data type in a namespace with the same name. Thus in the Lean files associated with this chapter, these definitions are made in the <code class="docutils literal notranslate"><span class="pre">GaussInt</span></code> namespace.</p> <p>Notice that here we are defining the interpretations of the notation <code class="docutils literal notranslate"><span class="pre">0</span></code>, <code class="docutils literal notranslate"><span class="pre">1</span></code>, <code class="docutils literal notranslate"><span class="pre">+</span></code>, <code class="docutils literal notranslate"><span class="pre">-</span></code>, and <code class="docutils literal notranslate"><span class="pre">*</span></code> directly, rather than naming them <code class="docutils literal notranslate"><span class="pre">GaussInt.zero</span></code> and the like and assigning the notation to those. It is often useful to have an explicit name for the definitions, for example, to use with <code class="docutils literal notranslate"><span class="pre">simp</span></code> and <code class="docutils literal notranslate"><span class="pre">rewrite</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">zero_def</span> <span class="o">:</span> <span class="o">(</span><span class="mi">0</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="bp">=</span> <span class="o">⟨</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">⟩</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">theorem</span> <span class="n">one_def</span> <span class="o">:</span> <span class="o">(</span><span class="mi">1</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="bp">=</span> <span class="o">⟨</span><span class="mi">1</span><span class="o">,</span> <span class="mi">0</span><span class="o">⟩</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">theorem</span> <span class="n">add_def</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">y</span> <span class="bp">=</span> <span class="o">⟨</span><span class="n">x.re</span> <span class="bp">+</span> <span class="n">y.re</span><span class="o">,</span> <span class="n">x.im</span> <span class="bp">+</span> <span class="n">y.im</span><span class="o">⟩</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">theorem</span> <span class="n">neg_def</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="bp">-</span><span class="n">x</span> <span class="bp">=</span> <span class="o">⟨</span><span class="bp">-</span><span class="n">x.re</span><span class="o">,</span> <span class="bp">-</span><span class="n">x.im</span><span class="o">⟩</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">theorem</span> <span class="n">mul_def</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">*</span> <span class="n">y</span> <span class="bp">=</span> <span class="o">⟨</span><span class="n">x.re</span> <span class="bp">*</span> <span class="n">y.re</span> <span class="bp">-</span> <span class="n">x.im</span> <span class="bp">*</span> <span class="n">y.im</span><span class="o">,</span> <span class="n">x.re</span> <span class="bp">*</span> <span class="n">y.im</span> <span class="bp">+</span> <span class="n">x.im</span> <span class="bp">*</span> <span class="n">y.re</span><span class="o">⟩</span> <span class="o">:=</span> <span class="n">rfl</span> </pre></div> </div> <p>It is also useful to name the rules that compute the real and imaginary parts, and to declare them to the simplifier.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">@[simp]</span> <span class="kd">theorem</span> <span class="n">zero_re</span> <span class="o">:</span> <span class="o">(</span><span class="mi">0</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span><span class="bp">.</span><span class="n">re</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">@[simp]</span> <span class="kd">theorem</span> <span class="n">zero_im</span> <span class="o">:</span> <span class="o">(</span><span class="mi">0</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span><span class="bp">.</span><span class="n">im</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">@[simp]</span> <span class="kd">theorem</span> <span class="n">one_re</span> <span class="o">:</span> <span class="o">(</span><span class="mi">1</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span><span class="bp">.</span><span class="n">re</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">@[simp]</span> <span class="kd">theorem</span> <span class="n">one_im</span> <span class="o">:</span> <span class="o">(</span><span class="mi">1</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span><span class="bp">.</span><span class="n">im</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">@[simp]</span> <span class="kd">theorem</span> <span class="n">add_re</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">x</span> <span class="bp">+</span> <span class="n">y</span><span class="o">)</span><span class="bp">.</span><span class="n">re</span> <span class="bp">=</span> <span class="n">x.re</span> <span class="bp">+</span> <span class="n">y.re</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">@[simp]</span> <span class="kd">theorem</span> <span class="n">add_im</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">x</span> <span class="bp">+</span> <span class="n">y</span><span class="o">)</span><span class="bp">.</span><span class="n">im</span> <span class="bp">=</span> <span class="n">x.im</span> <span class="bp">+</span> <span class="n">y.im</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">@[simp]</span> <span class="kd">theorem</span> <span class="n">neg_re</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="bp">-</span><span class="n">x</span><span class="o">)</span><span class="bp">.</span><span class="n">re</span> <span class="bp">=</span> <span class="bp">-</span><span class="n">x.re</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">@[simp]</span> <span class="kd">theorem</span> <span class="n">neg_im</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="bp">-</span><span class="n">x</span><span class="o">)</span><span class="bp">.</span><span class="n">im</span> <span class="bp">=</span> <span class="bp">-</span><span class="n">x.im</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">@[simp]</span> <span class="kd">theorem</span> <span class="n">mul_re</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">y</span><span class="o">)</span><span class="bp">.</span><span class="n">re</span> <span class="bp">=</span> <span class="n">x.re</span> <span class="bp">*</span> <span class="n">y.re</span> <span class="bp">-</span> <span class="n">x.im</span> <span class="bp">*</span> <span class="n">y.im</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">@[simp]</span> <span class="kd">theorem</span> <span class="n">mul_im</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">y</span><span class="o">)</span><span class="bp">.</span><span class="n">im</span> <span class="bp">=</span> <span class="n">x.re</span> <span class="bp">*</span> <span class="n">y.im</span> <span class="bp">+</span> <span class="n">x.im</span> <span class="bp">*</span> <span class="n">y.re</span> <span class="o">:=</span> <span class="n">rfl</span> </pre></div> </div> <p>It is now surprisingly easy to show that the Gaussian integers are an instance of a commutative ring. We are putting the structure concept to good use. Each particular Gaussian integer is an instance of the <code class="docutils literal notranslate"><span class="pre">gaussInt</span></code> structure, whereas the type <code class="docutils literal notranslate"><span class="pre">gaussInt</span></code> itself, together with the relevant operations, is an instance of the <code class="docutils literal notranslate"><span class="pre">CommRing</span></code> structure. The <code class="docutils literal notranslate"><span class="pre">CommRing</span></code> structure, in turn, extends the notational structures <code class="docutils literal notranslate"><span class="pre">Zero</span></code>, <code class="docutils literal notranslate"><span class="pre">One</span></code>, <code class="docutils literal notranslate"><span class="pre">Add</span></code>, <code class="docutils literal notranslate"><span class="pre">Neg</span></code>, and <code class="docutils literal notranslate"><span class="pre">Mul</span></code>.</p> <p>If you type <code class="docutils literal notranslate"><span class="pre">instance</span> <span class="pre">:</span> <span class="pre">CommRing</span> <span class="pre">gaussInt</span> <span class="pre">:=</span> <span class="pre">_</span></code>, click on the light bulb that appears in VS Code, and then ask Lean to fill in a skeleton for the structure definition, you will see a scary number of entries. Jumping to the definition of the structure, however, shows that many of the fields have default definitions that Lean will fill in for you automatically. The essential ones appear in the definition below. In each case, the relevant identity is proved by unfolding definitions, using the <code class="docutils literal notranslate"><span class="pre">ext</span></code> tactic to reduce the identities to their real and imaginary components, simplifying, and, if necessary, carrying out the relevant ring calculation in the integers.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="n">instCommRing</span> <span class="o">:</span> <span class="n">CommRing</span> <span class="n">gaussInt</span> <span class="n">where</span> <span class="n">zero</span> <span class="o">:=</span> <span class="mi">0</span> <span class="n">one</span> <span class="o">:=</span> <span class="mi">1</span> <span class="n">add</span> <span class="o">:=</span> <span class="o">(</span><span class="bp">·</span> <span class="bp">+</span> <span class="bp">·</span><span class="o">)</span> <span class="n">neg</span> <span class="n">x</span> <span class="o">:=</span> <span class="bp">-</span><span class="n">x</span> <span class="n">mul</span> <span class="o">:=</span> <span class="o">(</span><span class="bp">·</span> <span class="bp">*</span> <span class="bp">·</span><span class="o">)</span> <span class="n">add_assoc</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intros</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">simp</span> <span class="bp"><;></span> <span class="n">ring</span> <span class="n">zero_add</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">simp</span> <span class="n">add_zero</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">simp</span> <span class="n">add_left_neg</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">simp</span> <span class="n">add_comm</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intros</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">simp</span> <span class="bp"><;></span> <span class="n">ring</span> <span class="n">mul_assoc</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intros</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">simp</span> <span class="bp"><;></span> <span class="n">ring</span> <span class="n">one_mul</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">simp</span> <span class="n">mul_one</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">simp</span> <span class="n">left_distrib</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intros</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">simp</span> <span class="bp"><;></span> <span class="n">ring</span> <span class="n">right_distrib</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intros</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">simp</span> <span class="bp"><;></span> <span class="n">ring</span> <span class="n">mul_comm</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intros</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">simp</span> <span class="bp"><;></span> <span class="n">ring</span> <span class="n">zero_mul</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">mul_zero</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>Lean’s library defines the class of <em>nontrivial</em> types to be types with at least two distinct elements. In the context of a ring, this is equivalent to saying the the zero is not equal to the one. Since some common theorems depend on that fact, we may as well establish it now.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="o">:</span> <span class="n">Nontrivial</span> <span class="n">gaussInt</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">use</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">1</span> <span class="n">rw</span> <span class="o">[</span><span class="n">Ne</span><span class="o">,</span> <span class="n">gaussInt.ext_iff</span><span class="o">]</span> <span class="n">simp</span> </pre></div> </div> <p>We will now show that the Gaussian integers have an important additional property. A <em>Euclidean domain</em> is a ring <span class="math notranslate nohighlight">\(R\)</span> equipped with a <em>norm</em> function <span class="math notranslate nohighlight">\(N : R \to \mathbb{N}\)</span> with the following two properties:</p> <ul class="simple"> <li><p>For every <span class="math notranslate nohighlight">\(a\)</span> and <span class="math notranslate nohighlight">\(b \ne 0\)</span> in <span class="math notranslate nohighlight">\(R\)</span>, there are <span class="math notranslate nohighlight">\(q\)</span> and <span class="math notranslate nohighlight">\(r\)</span> in <span class="math notranslate nohighlight">\(R\)</span> such that <span class="math notranslate nohighlight">\(a = bq + r\)</span> and either <span class="math notranslate nohighlight">\(r = 0\)</span> or <cite>N(r) < N(b)</cite>.</p></li> <li><p>For every <span class="math notranslate nohighlight">\(a\)</span> and <span class="math notranslate nohighlight">\(b \ne 0\)</span>, <span class="math notranslate nohighlight">\(N(a) \le N(ab)\)</span>.</p></li> </ul> <p>The ring of integers <span class="math notranslate nohighlight">\(\Bbb{Z}\)</span> with <span class="math notranslate nohighlight">\(N(a) = |a|\)</span> is an archetypal example of a Euclidean domain. In that case, we can take <span class="math notranslate nohighlight">\(q\)</span> to be the result of integer division of <span class="math notranslate nohighlight">\(a\)</span> by <span class="math notranslate nohighlight">\(b\)</span> and <span class="math notranslate nohighlight">\(r\)</span> to be the remainder. These functions are defined in Lean so that the satisfy the following:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℤ</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">b</span> <span class="bp">*</span> <span class="o">(</span><span class="n">a</span> <span class="bp">/</span> <span class="n">b</span><span class="o">)</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">%</span> <span class="n">b</span> <span class="o">:=</span> <span class="n">Eq.symm</span> <span class="bp"><|</span> <span class="n">Int.ediv_add_emod</span> <span class="n">a</span> <span class="n">b</span> <span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℤ</span><span class="o">)</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">≠</span> <span class="mi">0</span> <span class="bp">→</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">a</span> <span class="bp">%</span> <span class="n">b</span> <span class="o">:=</span> <span class="n">Int.emod_nonneg</span> <span class="n">a</span> <span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℤ</span><span class="o">)</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">≠</span> <span class="mi">0</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp">%</span> <span class="n">b</span> <span class="bp"><</span> <span class="n">abs</span> <span class="n">b</span> <span class="o">:=</span> <span class="n">Int.emod_lt</span> <span class="n">a</span> </pre></div> </div> <p>In an arbitrary ring, an element <span class="math notranslate nohighlight">\(a\)</span> is said to be a <em>unit</em> if it divides <span class="math notranslate nohighlight">\(1\)</span>. A nonzero element <span class="math notranslate nohighlight">\(a\)</span> is said to be <em>irreducible</em> if it cannot be written in the form <span class="math notranslate nohighlight">\(a = bc\)</span> where neither <span class="math notranslate nohighlight">\(b\)</span> nor <span class="math notranslate nohighlight">\(c\)</span> is a unit. In the integers, every irreducible element <span class="math notranslate nohighlight">\(a\)</span> is <em>prime</em>, which is to say, whenever <span class="math notranslate nohighlight">\(a\)</span> divides a product <span class="math notranslate nohighlight">\(bc\)</span>, it divides either <span class="math notranslate nohighlight">\(b\)</span> or <span class="math notranslate nohighlight">\(c\)</span>. But in other rings this property can fail. In the ring <span class="math notranslate nohighlight">\(\Bbb{Z}[\sqrt{-5}]\)</span>, we have</p> <div class="math notranslate nohighlight"> \[6 = 2 \cdot 3 = (1 + \sqrt{-5})(1 - \sqrt{-5}),\]</div> <p>and the elements <span class="math notranslate nohighlight">\(2\)</span>, <span class="math notranslate nohighlight">\(3\)</span>, <span class="math notranslate nohighlight">\(1 + \sqrt{-5}\)</span>, and <span class="math notranslate nohighlight">\(1 - \sqrt{-5}\)</span> are all irreducible, but they are not prime. For example, <span class="math notranslate nohighlight">\(2\)</span> divides the product <span class="math notranslate nohighlight">\((1 + \sqrt{-5})(1 - \sqrt{-5})\)</span>, but it does not divide either factor. In particular, we no longer have unique factorization: the number <span class="math notranslate nohighlight">\(6\)</span> can be factored into irreducible elements in more than one way.</p> <p>In contrast, every Euclidean domain is a unique factorization domain, which implies that every irreducible element is prime. The axioms for a Euclidean domain imply that one can write any nonzero element as a finite product of irreducible elements. They also imply that one can use the Euclidean algorithm to find a greatest common divisor of any two nonzero elements <code class="docutils literal notranslate"><span class="pre">a</span></code> and <code class="docutils literal notranslate"><span class="pre">b</span></code>, i.e.~an element that is divisible by any other common divisor. This, in turn, implies that factorization into irreducible elements is unique up to multiplication by units.</p> <p>We now show that the Gaussian integers are a Euclidean domain with the norm defined by <span class="math notranslate nohighlight">\(N(a + bi) = (a + bi)(a - bi) = a^2 + b^2\)</span>. The Gaussian integer <span class="math notranslate nohighlight">\(a - bi\)</span> is called the <em>conjugate</em> of <span class="math notranslate nohighlight">\(a + bi\)</span>. It is not hard to check that for any complex numbers <span class="math notranslate nohighlight">\(x\)</span> and <span class="math notranslate nohighlight">\(y\)</span>, we have <span class="math notranslate nohighlight">\(N(xy) = N(x)N(y)\)</span>.</p> <p>To see that this definition of the norm makes the complex numbers a Euclidean domain, only the first property is challenging. Suppose we want to write <span class="math notranslate nohighlight">\(a + bi = (c + di) q + r\)</span> for suitable <span class="math notranslate nohighlight">\(q\)</span> and <span class="math notranslate nohighlight">\(r\)</span>. Treating <span class="math notranslate nohighlight">\(a + bi\)</span> and <span class="math notranslate nohighlight">\(c + di\)</span> are complex numbers, carry out the division</p> <div class="math notranslate nohighlight"> \[\frac{a + bi}{c + di} = \frac{(a + bi)(c - di)}{(c + di)(c-di)} = \frac{ac + bd}{c^2 + d^2} + \frac{bc -ad}{c^2+d^2} i.\]</div> <p>The real and imaginary parts might not be integers, but we can round them to the nearest integers <span class="math notranslate nohighlight">\(u\)</span> and <span class="math notranslate nohighlight">\(v\)</span>. We can then express the right-hand size as <span class="math notranslate nohighlight">\((u + vi) + (u' + v'i)\)</span>, where <span class="math notranslate nohighlight">\(u' + v'i\)</span> is the part left over. Note that we have <span class="math notranslate nohighlight">\(|u'| \le 1/2\)</span> and <span class="math notranslate nohighlight">\(|v'| \le 1/2\)</span>, and hence</p> <div class="math notranslate nohighlight"> \[N(u' + v' i) = (u')^2 + (v')^2 \le 1/4 + 1/4 \le 1/2.\]</div> <p>Multiplying through by <span class="math notranslate nohighlight">\(c + di\)</span>, we have</p> <div class="math notranslate nohighlight"> \[a + bi = (c + di) (u + vi) + (c + di) (u' + v'i).\]</div> <p>Setting <span class="math notranslate nohighlight">\(q = u + vi\)</span> and <span class="math notranslate nohighlight">\(r = (c + di) (u' + v'i)\)</span>, we have <span class="math notranslate nohighlight">\(a + bi = (c + di) q + r\)</span>, and we only need to bound <span class="math notranslate nohighlight">\(N(r)\)</span>:</p> <div class="math notranslate nohighlight"> \[N(r) = N(c + di)N(u' + v'i) \le N(c + di) \cdot 1/2 < N(c + di).\]</div> <p>The argument we just carried out requires viewing the Gaussian integers as a subset of the complex numbers. One option for formalizing it in Lean is therefore to embed the Gaussian integers in the complex numbers, embed the integers in the Gaussian integers, define the rounding function from the real numbers to the integers, and take great care to pass back and forth between these number systems appropriately. In fact, this is exactly the approach that is followed in mathlib, where the Gaussian integers themselves are constructed as a special case of a ring of <em>quadratic integers</em>. See the file <a class="reference external" href="https://github.com/leanprover-community/mathlib/blob/master/src/number_theory/zsqrtd/gaussian_int.lean">gaussian_int.lean</a>.</p> <p>Here we will instead carry out an argument that stays in the integers. This illustrates an choice one commonly faces when formalizing mathematics. Given an argument that requires concepts or machinery that is not already in the library, one has two choices: either formalizes the concepts or machinery needed, or adapt the argument to make use of concepts and machinery you already have. The first choice is generally a good investment of time when the results can be used in other contexts. Pragmatically speaking, however, sometimes seeking a more elementary proof is more efficient.</p> <p>The usual quotient-remainder theorem for the integers says that for every <span class="math notranslate nohighlight">\(a\)</span> and nonzero <span class="math notranslate nohighlight">\(b\)</span>, there are <span class="math notranslate nohighlight">\(q\)</span> and <span class="math notranslate nohighlight">\(r\)</span> such that <span class="math notranslate nohighlight">\(a = b q + r\)</span> and <span class="math notranslate nohighlight">\(0 \le r < b\)</span>. Here we will make use of the following variation, which says that there are <span class="math notranslate nohighlight">\(q'\)</span> and <span class="math notranslate nohighlight">\(r'\)</span> such that <span class="math notranslate nohighlight">\(a = b q' + r'\)</span> and <span class="math notranslate nohighlight">\(|r'| \le b/2\)</span>. You can check that if the value of <span class="math notranslate nohighlight">\(r\)</span> in the first statement satisfies <span class="math notranslate nohighlight">\(r \le b/2\)</span>, we can take <span class="math notranslate nohighlight">\(q' = q\)</span> and <span class="math notranslate nohighlight">\(r' = r\)</span>, and otherwise we can take <span class="math notranslate nohighlight">\(q' = q + 1\)</span> and <span class="math notranslate nohighlight">\(r' = r - b\)</span>. We are grateful to Heather Macbeth for suggesting the following more elegant approach, which avoids definition by cases. We simply add <code class="docutils literal notranslate"><span class="pre">b</span> <span class="pre">/</span> <span class="pre">2</span></code> to <code class="docutils literal notranslate"><span class="pre">a</span></code> before dividing and then subtract it from the remainder.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">div'</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℤ</span><span class="o">)</span> <span class="o">:=</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">/</span> <span class="mi">2</span><span class="o">)</span> <span class="bp">/</span> <span class="n">b</span> <span class="kd">def</span> <span class="n">mod'</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℤ</span><span class="o">)</span> <span class="o">:=</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">/</span> <span class="mi">2</span><span class="o">)</span> <span class="bp">%</span> <span class="n">b</span> <span class="bp">-</span> <span class="n">b</span> <span class="bp">/</span> <span class="mi">2</span> <span class="kd">theorem</span> <span class="n">div'_add_mod'</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℤ</span><span class="o">)</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">div'</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">mod'</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">a</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">div'</span><span class="o">,</span> <span class="n">mod'</span><span class="o">]</span> <span class="n">linarith</span> <span class="o">[</span><span class="n">Int.ediv_add_emod</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">/</span> <span class="mi">2</span><span class="o">)</span> <span class="n">b</span><span class="o">]</span> <span class="kd">theorem</span> <span class="n">abs_mod'_le</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℤ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">b</span><span class="o">)</span> <span class="o">:</span> <span class="n">abs</span> <span class="o">(</span><span class="n">mod'</span> <span class="n">a</span> <span class="n">b</span><span class="o">)</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">/</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mod'</span><span class="o">,</span> <span class="n">abs_le</span><span class="o">]</span> <span class="n">constructor</span> <span class="bp">·</span> <span class="n">linarith</span> <span class="o">[</span><span class="n">Int.emod_nonneg</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">/</span> <span class="mi">2</span><span class="o">)</span> <span class="n">h.ne'</span><span class="o">]</span> <span class="k">have</span> <span class="o">:=</span> <span class="n">Int.emod_lt_of_pos</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">/</span> <span class="mi">2</span><span class="o">)</span> <span class="n">h</span> <span class="k">have</span> <span class="o">:=</span> <span class="n">Int.ediv_add_emod</span> <span class="n">b</span> <span class="mi">2</span> <span class="k">have</span> <span class="o">:=</span> <span class="n">Int.emod_lt_of_pos</span> <span class="n">b</span> <span class="n">zero_lt_two</span> <span class="n">revert</span> <span class="n">this</span><span class="bp">;</span> <span class="n">intro</span> <span class="n">this</span> <span class="c1">-- FIXME, this should not be needed</span> <span class="n">linarith</span> </pre></div> </div> <p>Note the use of our old friend, <code class="docutils literal notranslate"><span class="pre">linarith</span></code>. We will also need to express <code class="docutils literal notranslate"><span class="pre">mod'</span></code> in terms of <code class="docutils literal notranslate"><span class="pre">div'</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">mod'_eq</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℤ</span><span class="o">)</span> <span class="o">:</span> <span class="n">mod'</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">-</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">div'</span> <span class="n">a</span> <span class="n">b</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">linarith</span> <span class="o">[</span><span class="n">div'_add_mod'</span> <span class="n">a</span> <span class="n">b</span><span class="o">]</span> </pre></div> </div> <p>We will use the fact that <span class="math notranslate nohighlight">\(x^2 + y^2\)</span> is equal to zero if and only if <span class="math notranslate nohighlight">\(x\)</span> and <span class="math notranslate nohighlight">\(y\)</span> are both zero. As an exercise, we ask you to prove that this holds in any ordered ring.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">sq_add_sq_eq_zero</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">LinearOrderedRing</span> <span class="n">α</span><span class="o">]</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="n">y</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">=</span> <span class="mi">0</span> <span class="bp">↔</span> <span class="n">x</span> <span class="bp">=</span> <span class="mi">0</span> <span class="bp">∧</span> <span class="n">y</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>We will put all the remaining definitions and theorems in this section in the <code class="docutils literal notranslate"><span class="pre">gaussInt</span></code> namespace. First, we define the <code class="docutils literal notranslate"><span class="pre">norm</span></code> function and ask you to establish some of its properties. The proofs are all short.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">norm</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:=</span> <span class="n">x.re</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="n">x.im</span> <span class="bp">^</span> <span class="mi">2</span> <span class="kd">@[simp]</span> <span class="kd">theorem</span> <span class="n">norm_nonneg</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">norm</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">norm_eq_zero</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="n">norm</span> <span class="n">x</span> <span class="bp">=</span> <span class="mi">0</span> <span class="bp">↔</span> <span class="n">x</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">norm_pos</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">norm</span> <span class="n">x</span> <span class="bp">↔</span> <span class="n">x</span> <span class="bp">≠</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">theorem</span> <span class="n">norm_mul</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="n">norm</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">y</span><span class="o">)</span> <span class="bp">=</span> <span class="n">norm</span> <span class="n">x</span> <span class="bp">*</span> <span class="n">norm</span> <span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>Next we define the conjugate function:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">conj</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="n">gaussInt</span> <span class="o">:=</span> <span class="o">⟨</span><span class="n">x.re</span><span class="o">,</span> <span class="bp">-</span><span class="n">x.im</span><span class="o">⟩</span> <span class="kd">@[simp]</span> <span class="kd">theorem</span> <span class="n">conj_re</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">conj</span> <span class="n">x</span><span class="o">)</span><span class="bp">.</span><span class="n">re</span> <span class="bp">=</span> <span class="n">x.re</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">@[simp]</span> <span class="kd">theorem</span> <span class="n">conj_im</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">conj</span> <span class="n">x</span><span class="o">)</span><span class="bp">.</span><span class="n">im</span> <span class="bp">=</span> <span class="bp">-</span><span class="n">x.im</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">theorem</span> <span class="n">norm_conj</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="n">norm</span> <span class="o">(</span><span class="n">conj</span> <span class="n">x</span><span class="o">)</span> <span class="bp">=</span> <span class="n">norm</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="o">[</span><span class="n">norm</span><span class="o">]</span> </pre></div> </div> <p>Finally, we define division for the Gaussian integers with the notation <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">/</span> <span class="pre">y</span></code>, that rounds the complex quotient to the nearest Gaussian integer. We use our bespoke <code class="docutils literal notranslate"><span class="pre">Int.div'</span></code> for that purpose. As we calculated above, if <code class="docutils literal notranslate"><span class="pre">x</span></code> is <span class="math notranslate nohighlight">\(a + bi\)</span> and <code class="docutils literal notranslate"><span class="pre">y</span></code> is <span class="math notranslate nohighlight">\(c + di\)</span>, then the real and imaginary parts of <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">/</span> <span class="pre">y</span></code> are the nearest integers to</p> <div class="math notranslate nohighlight"> \[\frac{ac + bd}{c^2 + d^2} \quad \text{and} \quad \frac{bc -ad}{c^2+d^2},\]</div> <p>respectively. Here the numerators are the real and imaginary parts of <span class="math notranslate nohighlight">\((a + bi) (c - di)\)</span>, and the denominators are both equal to the norm of <span class="math notranslate nohighlight">\(c + di\)</span>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="o">:</span> <span class="n">Div</span> <span class="n">gaussInt</span> <span class="o">:=</span> <span class="o">⟨</span><span class="k">fun</span> <span class="n">x</span> <span class="n">y</span> <span class="bp">=></span> <span class="o">⟨</span><span class="n">Int.div'</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">conj</span> <span class="n">y</span><span class="o">)</span><span class="bp">.</span><span class="n">re</span> <span class="o">(</span><span class="n">norm</span> <span class="n">y</span><span class="o">),</span> <span class="n">Int.div'</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">conj</span> <span class="n">y</span><span class="o">)</span><span class="bp">.</span><span class="n">im</span> <span class="o">(</span><span class="n">norm</span> <span class="n">y</span><span class="o">)⟩⟩</span> </pre></div> </div> <p>Having defined <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">/</span> <span class="pre">y</span></code>, We define <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">%</span> <span class="pre">y</span></code> to be the remainder, <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">-</span> <span class="pre">(x</span> <span class="pre">/</span> <span class="pre">y)</span> <span class="pre">*</span> <span class="pre">y</span></code>. As above, we record the definitions in the theorems <code class="docutils literal notranslate"><span class="pre">div_def</span></code> and <code class="docutils literal notranslate"><span class="pre">mod_def</span></code> so that we can use them with <code class="docutils literal notranslate"><span class="pre">simp</span></code> and <code class="docutils literal notranslate"><span class="pre">rewrite</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="o">:</span> <span class="n">Mod</span> <span class="n">gaussInt</span> <span class="o">:=</span> <span class="o">⟨</span><span class="k">fun</span> <span class="n">x</span> <span class="n">y</span> <span class="bp">=></span> <span class="n">x</span> <span class="bp">-</span> <span class="n">y</span> <span class="bp">*</span> <span class="o">(</span><span class="n">x</span> <span class="bp">/</span> <span class="n">y</span><span class="o">)⟩</span> <span class="kd">theorem</span> <span class="n">div_def</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">/</span> <span class="n">y</span> <span class="bp">=</span> <span class="o">⟨</span><span class="n">Int.div'</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">conj</span> <span class="n">y</span><span class="o">)</span><span class="bp">.</span><span class="n">re</span> <span class="o">(</span><span class="n">norm</span> <span class="n">y</span><span class="o">),</span> <span class="n">Int.div'</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">conj</span> <span class="n">y</span><span class="o">)</span><span class="bp">.</span><span class="n">im</span> <span class="o">(</span><span class="n">norm</span> <span class="n">y</span><span class="o">)⟩</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">theorem</span> <span class="n">mod_def</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">%</span> <span class="n">y</span> <span class="bp">=</span> <span class="n">x</span> <span class="bp">-</span> <span class="n">y</span> <span class="bp">*</span> <span class="o">(</span><span class="n">x</span> <span class="bp">/</span> <span class="n">y</span><span class="o">)</span> <span class="o">:=</span> <span class="n">rfl</span> </pre></div> </div> <p>These definitions immediately yield <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">=</span> <span class="pre">y</span> <span class="pre">*</span> <span class="pre">(x</span> <span class="pre">/</span> <span class="pre">y)</span> <span class="pre">+</span> <span class="pre">x</span> <span class="pre">%</span> <span class="pre">y</span></code> for every <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code>, so all we need to do is show that the norm of <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">%</span> <span class="pre">y</span></code> is less than the norm of <code class="docutils literal notranslate"><span class="pre">y</span></code> when <code class="docutils literal notranslate"><span class="pre">y</span></code> is not zero.</p> <p>We just defined the real and imaginary parts of <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">/</span> <span class="pre">y</span></code> to be <code class="docutils literal notranslate"><span class="pre">div'</span> <span class="pre">(x</span> <span class="pre">*</span> <span class="pre">conj</span> <span class="pre">y).re</span> <span class="pre">(norm</span> <span class="pre">y)</span></code> and <code class="docutils literal notranslate"><span class="pre">div'</span> <span class="pre">(x</span> <span class="pre">*</span> <span class="pre">conj</span> <span class="pre">y).im</span> <span class="pre">(norm</span> <span class="pre">y)</span></code>, respectively. Calculating, we have</p> <blockquote> <div><p><code class="docutils literal notranslate"><span class="pre">(x</span> <span class="pre">%</span> <span class="pre">y)</span> <span class="pre">*</span> <span class="pre">conj</span> <span class="pre">y</span> <span class="pre">=</span> <span class="pre">(x</span> <span class="pre">-</span> <span class="pre">x</span> <span class="pre">/</span> <span class="pre">y</span> <span class="pre">*</span> <span class="pre">y)</span> <span class="pre">*</span> <span class="pre">conj</span> <span class="pre">y</span> <span class="pre">=</span> <span class="pre">x</span> <span class="pre">*</span> <span class="pre">conj</span> <span class="pre">y</span> <span class="pre">-</span> <span class="pre">x</span> <span class="pre">*</span> <span class="pre">(y</span> <span class="pre">*</span> <span class="pre">conj</span> <span class="pre">j)</span></code></p> </div></blockquote> <p>The real and imaginary parts of the right-hand side are exactly <code class="docutils literal notranslate"><span class="pre">mod'</span> <span class="pre">(x</span> <span class="pre">*</span> <span class="pre">conj</span> <span class="pre">y).re</span> <span class="pre">(norm</span> <span class="pre">y)</span></code> and <code class="docutils literal notranslate"><span class="pre">mod'</span> <span class="pre">(x</span> <span class="pre">*</span> <span class="pre">conj</span> <span class="pre">y).im</span> <span class="pre">(norm</span> <span class="pre">y)</span></code>. By the properties of <code class="docutils literal notranslate"><span class="pre">div'</span></code> and <code class="docutils literal notranslate"><span class="pre">mod'</span></code>, these are guaranteed to be less than or equal to <code class="docutils literal notranslate"><span class="pre">norm</span> <span class="pre">y</span> <span class="pre">/</span> <span class="pre">2</span></code>. So we have</p> <blockquote> <div><p><code class="docutils literal notranslate"><span class="pre">norm</span> <span class="pre">((x</span> <span class="pre">%</span> <span class="pre">y)</span> <span class="pre">*</span> <span class="pre">conj</span> <span class="pre">y)</span> <span class="pre">≤</span> <span class="pre">(norm</span> <span class="pre">y</span> <span class="pre">/</span> <span class="pre">2)^2</span> <span class="pre">+</span> <span class="pre">(norm</span> <span class="pre">y</span> <span class="pre">/</span> <span class="pre">2)^2</span> <span class="pre">≤</span> <span class="pre">(norm</span> <span class="pre">y</span> <span class="pre">/</span> <span class="pre">2)</span> <span class="pre">*</span> <span class="pre">norm</span> <span class="pre">y</span></code>.</p> </div></blockquote> <p>On the other hand, we have</p> <blockquote> <div><p><code class="docutils literal notranslate"><span class="pre">norm</span> <span class="pre">((x</span> <span class="pre">%</span> <span class="pre">y)</span> <span class="pre">*</span> <span class="pre">conj</span> <span class="pre">y)</span> <span class="pre">=</span> <span class="pre">norm</span> <span class="pre">(x</span> <span class="pre">%</span> <span class="pre">y)</span> <span class="pre">*</span> <span class="pre">norm</span> <span class="pre">(conj</span> <span class="pre">y)</span> <span class="pre">=</span> <span class="pre">norm</span> <span class="pre">(x</span> <span class="pre">%</span> <span class="pre">y)</span> <span class="pre">*</span> <span class="pre">norm</span> <span class="pre">y</span></code>.</p> </div></blockquote> <p>Dividing through by <code class="docutils literal notranslate"><span class="pre">norm</span> <span class="pre">y</span></code> we have <code class="docutils literal notranslate"><span class="pre">norm</span> <span class="pre">(x</span> <span class="pre">%</span> <span class="pre">y)</span> <span class="pre">≤</span> <span class="pre">(norm</span> <span class="pre">y)</span> <span class="pre">/</span> <span class="pre">2</span> <span class="pre"><</span> <span class="pre">norm</span> <span class="pre">y</span></code>, as required.</p> <p>This messy calculation is carried out in the next proof. We encourage you to step through the details and see if you can find a nicer argument.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">norm_mod_lt</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">{</span><span class="n">y</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">}</span> <span class="o">(</span><span class="n">hy</span> <span class="o">:</span> <span class="n">y</span> <span class="bp">≠</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">x</span> <span class="bp">%</span> <span class="n">y</span><span class="o">)</span><span class="bp">.</span><span class="n">norm</span> <span class="bp"><</span> <span class="n">y.norm</span> <span class="o">:=</span> <span class="kd">by</span> <span class="k">have</span> <span class="n">norm_y_pos</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">norm</span> <span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rwa</span> <span class="o">[</span><span class="n">norm_pos</span><span class="o">]</span> <span class="k">have</span> <span class="n">H1</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">%</span> <span class="n">y</span> <span class="bp">*</span> <span class="n">conj</span> <span class="n">y</span> <span class="bp">=</span> <span class="o">⟨</span><span class="n">Int.mod'</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">conj</span> <span class="n">y</span><span class="o">)</span><span class="bp">.</span><span class="n">re</span> <span class="o">(</span><span class="n">norm</span> <span class="n">y</span><span class="o">),</span> <span class="n">Int.mod'</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">conj</span> <span class="n">y</span><span class="o">)</span><span class="bp">.</span><span class="n">im</span> <span class="o">(</span><span class="n">norm</span> <span class="n">y</span><span class="o">)⟩</span> <span class="bp">·</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">simp</span> <span class="o">[</span><span class="n">Int.mod'_eq</span><span class="o">,</span> <span class="n">mod_def</span><span class="o">,</span> <span class="n">div_def</span><span class="o">,</span> <span class="n">norm</span><span class="o">]</span> <span class="bp"><;></span> <span class="n">ring</span> <span class="k">have</span> <span class="n">H2</span> <span class="o">:</span> <span class="n">norm</span> <span class="o">(</span><span class="n">x</span> <span class="bp">%</span> <span class="n">y</span><span class="o">)</span> <span class="bp">*</span> <span class="n">norm</span> <span class="n">y</span> <span class="bp">≤</span> <span class="n">norm</span> <span class="n">y</span> <span class="bp">/</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">norm</span> <span class="n">y</span> <span class="bp">·</span> <span class="k">calc</span> <span class="n">norm</span> <span class="o">(</span><span class="n">x</span> <span class="bp">%</span> <span class="n">y</span><span class="o">)</span> <span class="bp">*</span> <span class="n">norm</span> <span class="n">y</span> <span class="bp">=</span> <span class="n">norm</span> <span class="o">(</span><span class="n">x</span> <span class="bp">%</span> <span class="n">y</span> <span class="bp">*</span> <span class="n">conj</span> <span class="n">y</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="n">only</span> <span class="o">[</span><span class="n">norm_mul</span><span class="o">,</span> <span class="n">norm_conj</span><span class="o">]</span> <span class="n">_</span> <span class="bp">=</span> <span class="n">abs</span> <span class="o">(</span><span class="n">Int.mod'</span> <span class="o">(</span><span class="n">x.re</span> <span class="bp">*</span> <span class="n">y.re</span> <span class="bp">+</span> <span class="n">x.im</span> <span class="bp">*</span> <span class="n">y.im</span><span class="o">)</span> <span class="o">(</span><span class="n">norm</span> <span class="n">y</span><span class="o">))</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="n">abs</span> <span class="o">(</span><span class="n">Int.mod'</span> <span class="o">(</span><span class="bp">-</span><span class="o">(</span><span class="n">x.re</span> <span class="bp">*</span> <span class="n">y.im</span><span class="o">)</span> <span class="bp">+</span> <span class="n">x.im</span> <span class="bp">*</span> <span class="n">y.re</span><span class="o">)</span> <span class="o">(</span><span class="n">norm</span> <span class="n">y</span><span class="o">))</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="o">[</span><span class="n">H1</span><span class="o">,</span> <span class="n">norm</span><span class="o">,</span> <span class="n">sq_abs</span><span class="o">]</span> <span class="n">_</span> <span class="bp">≤</span> <span class="o">(</span><span class="n">y.norm</span> <span class="bp">/</span> <span class="mi">2</span><span class="o">)</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="o">(</span><span class="n">y.norm</span> <span class="bp">/</span> <span class="mi">2</span><span class="o">)</span> <span class="bp">^</span> <span class="mi">2</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">gcongr</span> <span class="bp"><;></span> <span class="n">apply</span> <span class="n">Int.abs_mod'_le</span> <span class="n">_</span> <span class="n">_</span> <span class="n">norm_y_pos</span> <span class="n">_</span> <span class="bp">=</span> <span class="n">norm</span> <span class="n">y</span> <span class="bp">/</span> <span class="mi">2</span> <span class="bp">*</span> <span class="o">(</span><span class="n">norm</span> <span class="n">y</span> <span class="bp">/</span> <span class="mi">2</span> <span class="bp">*</span> <span class="mi">2</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">ring</span> <span class="n">_</span> <span class="bp">≤</span> <span class="n">norm</span> <span class="n">y</span> <span class="bp">/</span> <span class="mi">2</span> <span class="bp">*</span> <span class="n">norm</span> <span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">gcongr</span><span class="bp">;</span> <span class="n">apply</span> <span class="n">Int.ediv_mul_le</span><span class="bp">;</span> <span class="n">norm_num</span> <span class="k">calc</span> <span class="n">norm</span> <span class="o">(</span><span class="n">x</span> <span class="bp">%</span> <span class="n">y</span><span class="o">)</span> <span class="bp">≤</span> <span class="n">norm</span> <span class="n">y</span> <span class="bp">/</span> <span class="mi">2</span> <span class="o">:=</span> <span class="n">le_of_mul_le_mul_right</span> <span class="n">H2</span> <span class="n">norm_y_pos</span> <span class="n">_</span> <span class="bp"><</span> <span class="n">norm</span> <span class="n">y</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">Int.ediv_lt_of_lt_mul</span> <span class="bp">·</span> <span class="n">norm_num</span> <span class="bp">·</span> <span class="n">linarith</span> </pre></div> </div> <p>We are in the home stretch. Our <code class="docutils literal notranslate"><span class="pre">norm</span></code> function maps Gaussian integers to nonnegative integers. We need a function that maps Gaussian integers to natural numbers, and we obtain that by composing <code class="docutils literal notranslate"><span class="pre">norm</span></code> with the function <code class="docutils literal notranslate"><span class="pre">Int.natAbs</span></code>, which maps integers to the natural numbers. The first of the next two lemmas establishes that mapping the norm to the natural numbers and back to the integers does not change the value. The second one re-expresses the fact that the norm is decreasing.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">coe_natAbs_norm</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">x.norm.natAbs</span> <span class="o">:</span> <span class="n">ℤ</span><span class="o">)</span> <span class="bp">=</span> <span class="n">x.norm</span> <span class="o">:=</span> <span class="n">Int.natAbs_of_nonneg</span> <span class="o">(</span><span class="n">norm_nonneg</span> <span class="n">_</span><span class="o">)</span> <span class="kd">theorem</span> <span class="n">natAbs_norm_mod_lt</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">(</span><span class="n">hy</span> <span class="o">:</span> <span class="n">y</span> <span class="bp">≠</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">x</span> <span class="bp">%</span> <span class="n">y</span><span class="o">)</span><span class="bp">.</span><span class="n">norm.natAbs</span> <span class="bp"><</span> <span class="n">y.norm.natAbs</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">Int.ofNat_lt.1</span> <span class="n">simp</span> <span class="n">only</span> <span class="o">[</span><span class="n">Int.coe_natAbs</span><span class="o">,</span> <span class="n">abs_of_nonneg</span><span class="o">,</span> <span class="n">norm_nonneg</span><span class="o">]</span> <span class="n">apply</span> <span class="n">norm_mod_lt</span> <span class="n">x</span> <span class="n">hy</span> </pre></div> </div> <p>We also need to establish the second key property of the norm function on a Euclidean domain.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">not_norm_mul_left_lt_norm</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">{</span><span class="n">y</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">}</span> <span class="o">(</span><span class="n">hy</span> <span class="o">:</span> <span class="n">y</span> <span class="bp">≠</span> <span class="mi">0</span><span class="o">)</span> <span class="o">:</span> <span class="bp">¬</span><span class="o">(</span><span class="n">norm</span> <span class="o">(</span><span class="n">x</span> <span class="bp">*</span> <span class="n">y</span><span class="o">))</span><span class="bp">.</span><span class="n">natAbs</span> <span class="bp"><</span> <span class="o">(</span><span class="n">norm</span> <span class="n">x</span><span class="o">)</span><span class="bp">.</span><span class="n">natAbs</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">not_lt_of_ge</span> <span class="n">rw</span> <span class="o">[</span><span class="n">norm_mul</span><span class="o">,</span> <span class="n">Int.natAbs_mul</span><span class="o">]</span> <span class="n">apply</span> <span class="n">le_mul_of_one_le_right</span> <span class="o">(</span><span class="n">Nat.zero_le</span> <span class="n">_</span><span class="o">)</span> <span class="n">apply</span> <span class="n">Int.ofNat_le.1</span> <span class="n">rw</span> <span class="o">[</span><span class="n">coe_natAbs_norm</span><span class="o">]</span> <span class="n">exact</span> <span class="n">Int.add_one_le_of_lt</span> <span class="o">((</span><span class="n">norm_pos</span> <span class="n">_</span><span class="o">)</span><span class="bp">.</span><span class="n">mpr</span> <span class="n">hy</span><span class="o">)</span> </pre></div> </div> <p>We can now put it together to show that the Gaussian integers are an instance of a Euclidean domain. We use the quotient and remainder function we have defined. The mathlib definition of a Euclidean domain is more general than the one above in that it allows us to show that remainder decreases with respect to any well-founded measure. Comparing the values of a norm function that returns natural numbers is just one instance of such a measure, and in that case, the required properties are the theorems <code class="docutils literal notranslate"><span class="pre">natAbs_norm_mod_lt</span></code> and <code class="docutils literal notranslate"><span class="pre">not_norm_mul_left_lt_norm</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="o">:</span> <span class="n">EuclideanDomain</span> <span class="n">gaussInt</span> <span class="o">:=</span> <span class="o">{</span> <span class="n">gaussInt.instCommRing</span> <span class="k">with</span> <span class="n">quotient</span> <span class="o">:=</span> <span class="o">(</span><span class="bp">·</span> <span class="bp">/</span> <span class="bp">·</span><span class="o">)</span> <span class="n">remainder</span> <span class="o">:=</span> <span class="o">(</span><span class="bp">·</span> <span class="bp">%</span> <span class="bp">·</span><span class="o">)</span> <span class="n">quotient_mul_add_remainder_eq</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">x</span> <span class="n">y</span> <span class="bp">=></span> <span class="kd">by</span> <span class="n">simp</span> <span class="n">only</span><span class="bp">;</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mod_def</span><span class="o">,</span> <span class="n">add_comm</span><span class="o">,</span> <span class="n">sub_add_cancel</span><span class="o">]</span> <span class="n">quotient_zero</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="kd">by</span> <span class="n">simp</span> <span class="o">[</span><span class="n">div_def</span><span class="o">,</span> <span class="n">norm</span><span class="o">,</span> <span class="n">Int.div'</span><span class="o">]</span> <span class="n">rfl</span> <span class="n">r</span> <span class="o">:=</span> <span class="n">Measure</span> <span class="o">(</span><span class="n">Int.natAbs</span> <span class="bp">∘</span> <span class="n">norm</span><span class="o">)</span> <span class="n">r_wellFounded</span> <span class="o">:=</span> <span class="o">(</span><span class="n">measure</span> <span class="o">(</span><span class="n">Int.natAbs</span> <span class="bp">∘</span> <span class="n">norm</span><span class="o">))</span><span class="bp">.</span><span class="mi">2</span> <span class="n">remainder_lt</span> <span class="o">:=</span> <span class="n">natAbs_norm_mod_lt</span> <span class="n">mul_left_not_lt</span> <span class="o">:=</span> <span class="n">not_norm_mul_left_lt_norm</span> <span class="o">}</span> </pre></div> </div> <p>An immediate payoff is that we now know that, in the Gaussian integers, the notions of being prime and being irreducible coincide.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">gaussInt</span><span class="o">)</span> <span class="o">:</span> <span class="n">Irreducible</span> <span class="n">x</span> <span class="bp">↔</span> <span class="n">Prime</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">PrincipalIdealRing.irreducible_iff_prime</span> </pre></div> </div> </section> </section> </div> </div> <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> <a href="C05_Number_Theory.html" class="btn btn-neutral float-left" title="5. Number Theory" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> <a href="C07_Hierarchies.html" class="btn btn-neutral float-right" title="7. Hierarchies" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> </div> <hr/> <div role="contentinfo"> <p>© Copyright 2020, Jeremy Avigad, Kevin Buzzard, Robert Y. Lewis, Patrick Massot.</p> </div> Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. </footer> </div> </div> </section> </div> <script> jQuery(function () { SphinxRtdTheme.Navigation.enable(true); }); </script> </body> </html>
-
-
-
@@ -0,0 +1,1010 @@<!DOCTYPE html> <html class="writer-html5" lang="en" > <head> <meta charset="utf-8" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>7. Hierarchies — Mathematics in Lean 0.1 documentation</title> <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> <link rel="stylesheet" href="_static/css/custom.css" type="text/css" /> <link rel="shortcut icon" href="_static/favicon.ico"/> <!--[if lt IE 9]> <script src="_static/js/html5shiv.min.js"></script> <![endif]--> <script src="_static/jquery.js"></script> <script src="_static/_sphinx_javascript_frameworks_compat.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script src="_static/doctools.js"></script> <script src="_static/sphinx_highlight.js"></script> <script src="_static/js/theme.js"></script> <link rel="index" title="Index" href="genindex.html" /> <link rel="search" title="Search" href="search.html" /> <link rel="next" title="8. Topology" href="C08_Topology.html" /> <link rel="prev" title="6. Structures" href="C06_Structures.html" /> </head> <body class="wy-body-for-nav"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search" > <a href="index.html" class="icon icon-home"> Mathematics in Lean </a> <div role="search"> <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> <ul class="current"> <li class="toctree-l1"><a class="reference internal" href="C01_Introduction.html">1. Introduction</a></li> <li class="toctree-l1"><a class="reference internal" href="C02_Basics.html">2. Basics</a></li> <li class="toctree-l1"><a class="reference internal" href="C03_Logic.html">3. Logic</a></li> <li class="toctree-l1"><a class="reference internal" href="C04_Sets_and_Functions.html">4. Sets and Functions</a></li> <li class="toctree-l1"><a class="reference internal" href="C05_Number_Theory.html">5. Number Theory</a></li> <li class="toctree-l1"><a class="reference internal" href="C06_Structures.html">6. Structures</a></li> <li class="toctree-l1 current"><a class="current reference internal" href="#">7. Hierarchies</a><ul> <li class="toctree-l2"><a class="reference internal" href="#basics">7.1. Basics</a></li> <li class="toctree-l2"><a class="reference internal" href="#morphisms">7.2. Morphisms</a></li> <li class="toctree-l2"><a class="reference internal" href="#sub-objects">7.3. Sub-objects</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="C08_Topology.html">8. Topology</a></li> <li class="toctree-l1"><a class="reference internal" href="C09_Differential_Calculus.html">9. Differential Calculus</a></li> </ul> <ul> <li class="toctree-l1"><a class="reference internal" href="genindex.html">Index</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="index.html">Mathematics in Lean</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="Page navigation"> <ul class="wy-breadcrumbs"> <li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li> <li class="breadcrumb-item active"><span class="section-number">7. </span>Hierarchies</li> <li class="wy-breadcrumbs-aside"> <a href="_sources/C07_Hierarchies.rst.txt" rel="nofollow"> View page source</a> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <section id="hierarchies"> <span id="id1"></span><h1><span class="section-number">7. </span>Hierarchies<a class="headerlink" href="#hierarchies" title="Permalink to this heading"></a></h1> <p>We have seen in <a class="reference internal" href="C06_Structures.html#structures"><span class="std std-numref">Chapter 6</span></a> how to define the class of groups and build instances of this class, and then how to build an instance of the commutative ring class. But of course there is a hierarchy here: a commutative ring is in particular an additive group. In this chapter we will study how to build such hierarchies. They appear in all branches of mathematics but in this chapter the emphasis will be on algebraic examples.</p> <p>It may seem premature to discuss how to build hierarchies before more discussions about using existing hierarchies. But some understanding of the technology underlying hierarchies is required to use them. So you should probably still read this chapter, but without trying too hard to remember everything on your first read, then read the following chapters and come back here for a second reading.</p> <p>In this chapter, we will redefine (simpler versions of) many things that appear in Mathlib so we will used indices to distinguish our version. For instance we will have <code class="docutils literal notranslate"><span class="pre">Ring₁</span></code> as our version of <code class="docutils literal notranslate"><span class="pre">Ring</span></code>. Since we will gradually explain more powerful ways of formalizing structures, those indices will sometimes grow beyond one.</p> <section id="basics"> <span id="section-hierarchies-basics"></span><h2><span class="section-number">7.1. </span>Basics<a class="headerlink" href="#basics" title="Permalink to this heading"></a></h2> <p>At the very bottom of all hierarchies in Lean, we find data-carrying classes. The following class records that the given type <code class="docutils literal notranslate"><span class="pre">α</span></code> is endowed with a distinguished element called <code class="docutils literal notranslate"><span class="pre">one</span></code>. At this stage, it has no property at all.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">One₁</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="n">where</span> <span class="sd">/-- The element one -/</span> <span class="n">one</span> <span class="o">:</span> <span class="n">α</span> </pre></div> </div> <p>Since we’ll make a much heavier use of classes in this chapter, we need to understand some more details about what the <code class="docutils literal notranslate"><span class="pre">class</span></code> command is doing. First, the <code class="docutils literal notranslate"><span class="pre">class</span></code> command above defines a structure <code class="docutils literal notranslate"><span class="pre">One₁</span></code> with parameter <code class="docutils literal notranslate"><span class="pre">α</span> <span class="pre">:</span> <span class="pre">Type</span></code> and a single field <code class="docutils literal notranslate"><span class="pre">one</span></code>. It also mark this structure as a class so that arguments of type <code class="docutils literal notranslate"><span class="pre">One₁</span> <span class="pre">α</span></code> for some type <code class="docutils literal notranslate"><span class="pre">α</span></code> will be inferrable using the instance resolution procedure, as long as they are marked as instance-implicit, ie appear between square brackets. Those two effects could also have been achieved using the <code class="docutils literal notranslate"><span class="pre">structure</span></code> command with <code class="docutils literal notranslate"><span class="pre">class</span></code> attribute, ie writing <code class="docutils literal notranslate"><span class="pre">@[class]</span> <span class="pre">structure</span></code> instance of <code class="docutils literal notranslate"><span class="pre">class</span></code>. But the class command also ensures that <code class="docutils literal notranslate"><span class="pre">One₁</span> <span class="pre">α</span></code> appears as an instance-implicit argument in its own fields. Compare:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="n">One₁.one</span> <span class="c1">-- One₁.one {α : Type} [self : One₁ α] : α</span> <span class="kd">@[class]</span> <span class="kd">structure</span> <span class="n">One₂</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="n">where</span> <span class="sd">/-- The element one -/</span> <span class="n">one</span> <span class="o">:</span> <span class="n">α</span> <span class="k">#check</span> <span class="n">One₂.one</span> </pre></div> </div> <p>In the second check, we can see that <code class="docutils literal notranslate"><span class="pre">self</span> <span class="pre">:</span> <span class="pre">One₂</span> <span class="pre">α</span></code> is an explicit argument. Let us make sure the first version is indeed usable without any explicit argument.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">One₁</span> <span class="n">α</span><span class="o">]</span> <span class="o">:</span> <span class="n">α</span> <span class="o">:=</span> <span class="n">One₁.one</span> </pre></div> </div> <p>Remark: in the above example, the argument <code class="docutils literal notranslate"><span class="pre">One₁</span> <span class="pre">α</span></code> is marked as instance-implicit, which is a bit silly since this affects only <em>uses</em> of the declaration and declaration created by the <code class="docutils literal notranslate"><span class="pre">example</span></code> command cannot be used. However it allows to avoid giving a name to that argument and, more importantly, it starts installing the good habit of marking <code class="docutils literal notranslate"><span class="pre">One₁</span> <span class="pre">α</span></code> arguments as instance-implicit.</p> <p>Another remark is that all this will work only when Lean knows what is <code class="docutils literal notranslate"><span class="pre">α</span></code>. In the above example, leaving out the type ascription <code class="docutils literal notranslate"><span class="pre">:</span> <span class="pre">α</span></code> would generate an error message like: <code class="docutils literal notranslate"><span class="pre">typeclass</span> <span class="pre">instance</span> <span class="pre">problem</span> <span class="pre">is</span> <span class="pre">stuck,</span> <span class="pre">it</span> <span class="pre">is</span> <span class="pre">often</span> <span class="pre">due</span> <span class="pre">to</span> <span class="pre">metavariables</span> <span class="pre">One₁</span> <span class="pre">(?m.263</span> <span class="pre">α)</span></code> where <code class="docutils literal notranslate"><span class="pre">?m.263</span> <span class="pre">α</span></code> means “some type depending on <code class="docutils literal notranslate"><span class="pre">α</span></code>” (and 263 is simply an auto-generated index that would be useful to distinguish between several unknown things). Another way to avoid this issue would be to use a type annotation, as in:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">One₁</span> <span class="n">α</span><span class="o">]</span> <span class="o">:=</span> <span class="o">(</span><span class="n">One₁.one</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> </pre></div> </div> <p>You may have already encountered that issue when playing with limits of sequences in <a class="reference internal" href="C03_Logic.html#sequences-and-convergence"><span class="std std-numref">Section 3.6</span></a> if you tried to state for instance that <code class="docutils literal notranslate"><span class="pre">0</span> <span class="pre"><</span> <span class="pre">1</span></code> without telling Lean whether you meant this inequality to be about natural numbers or real numbers.</p> <p>Our next task is to assign a notation to <code class="docutils literal notranslate"><span class="pre">One₁.one</span></code>. This we don’t want collisions with the builtin notation for <code class="docutils literal notranslate"><span class="pre">1</span></code>, we will use <code class="docutils literal notranslate"><span class="pre">𝟙</span></code>. This is achieved by the following command where the first line tells Lean to use the documentation of <code class="docutils literal notranslate"><span class="pre">One₁.one</span></code> as documentation for the symbol <code class="docutils literal notranslate"><span class="pre">𝟙</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">@[inherit_doc]</span> <span class="kd">notation</span> <span class="s2">"𝟙"</span> <span class="bp">=></span> <span class="n">One₁.one</span> <span class="kd">example</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">}</span> <span class="o">[</span><span class="n">One₁</span> <span class="n">α</span><span class="o">]</span> <span class="o">:</span> <span class="n">α</span> <span class="o">:=</span> <span class="mi">𝟙</span> <span class="kd">example</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">}</span> <span class="o">[</span><span class="n">One₁</span> <span class="n">α</span><span class="o">]</span> <span class="o">:</span> <span class="o">(</span><span class="mi">𝟙</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="bp">=</span> <span class="mi">𝟙</span> <span class="o">:=</span> <span class="n">rfl</span> </pre></div> </div> <p>We now want a data-carrying class recording a binary operation. We don’t want to choose between addition and multiplication for now so we’ll use diamond.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">Dia₁</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="n">where</span> <span class="n">dia</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">α</span> <span class="kd">infixl</span><span class="o">:</span><span class="mi">70</span> <span class="s2">" ⋄ "</span> <span class="bp">=></span> <span class="n">Dia₁.dia</span> </pre></div> </div> <p>As in the <code class="docutils literal notranslate"><span class="pre">One₁</span></code> example, the operation has no property at all at this stage. Let us now define the class of semigroup structures where the operation is denoted by <code class="docutils literal notranslate"><span class="pre">⋄</span></code>. For now, we define it by hand as a structure with two fields, a <code class="docutils literal notranslate"><span class="pre">Dia₁</span></code> instance and some <code class="docutils literal notranslate"><span class="pre">Prop</span></code>-valued field <code class="docutils literal notranslate"><span class="pre">dia_assoc</span></code> asserting associativity of <code class="docutils literal notranslate"><span class="pre">⋄</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">Semigroup₁</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="n">where</span> <span class="n">toDia₁</span> <span class="o">:</span> <span class="n">Dia₁</span> <span class="n">α</span> <span class="sd">/-- Diamond is associative -/</span> <span class="n">dia_assoc</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">a</span> <span class="bp">⋄</span> <span class="n">b</span> <span class="bp">⋄</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">⋄</span> <span class="o">(</span><span class="n">b</span> <span class="bp">⋄</span> <span class="n">c</span><span class="o">)</span> </pre></div> </div> <p>Note that while stating <cite>dia_assoc</cite>, the previously defined field <cite>toDia₁</cite> is in the local context hence can be used when Lean searches for an instance of <cite>Dia₁ α</cite> to make sense of <cite>a ⋄ b</cite>. However this <cite>toDia₁</cite> field does not become part of the type class instances database. Hence doing <code class="docutils literal notranslate"><span class="pre">example</span> <span class="pre">{α</span> <span class="pre">:</span> <span class="pre">Type}</span> <span class="pre">[Semigroup₁</span> <span class="pre">α]</span> <span class="pre">(a</span> <span class="pre">b</span> <span class="pre">:</span> <span class="pre">α)</span> <span class="pre">:</span> <span class="pre">α</span> <span class="pre">:=</span> <span class="pre">a</span> <span class="pre">⋄</span> <span class="pre">b</span></code> would fail with error message <code class="docutils literal notranslate"><span class="pre">failed</span> <span class="pre">to</span> <span class="pre">synthesize</span> <span class="pre">instance</span> <span class="pre">Dia₁</span> <span class="pre">α</span></code>.</p> <p>We can fix this by adding the <code class="docutils literal notranslate"><span class="pre">instance</span></code> attribute later.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">attribute</span> <span class="o">[</span><span class="kd">instance</span><span class="o">]</span> <span class="n">Semigroup₁.toDia₁</span> <span class="kd">example</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">}</span> <span class="o">[</span><span class="n">Semigroup₁</span> <span class="n">α</span><span class="o">]</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="o">:</span> <span class="n">α</span> <span class="o">:=</span> <span class="n">a</span> <span class="bp">⋄</span> <span class="n">b</span> </pre></div> </div> <p>Before building up, we need a more convenient way to extend structures than explicitly writing fields like <cite>toDia₁</cite> and adding the instance attribute by hand. The <code class="docutils literal notranslate"><span class="pre">class</span></code> supports this using the <code class="docutils literal notranslate"><span class="pre">extends</span></code> syntax as in:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">Semigroup₂</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">Dia₁</span> <span class="n">α</span> <span class="n">where</span> <span class="sd">/-- Diamond is associative -/</span> <span class="n">dia_assoc</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">a</span> <span class="bp">⋄</span> <span class="n">b</span> <span class="bp">⋄</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">⋄</span> <span class="o">(</span><span class="n">b</span> <span class="bp">⋄</span> <span class="n">c</span><span class="o">)</span> <span class="kd">example</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">}</span> <span class="o">[</span><span class="n">Semigroup₂</span> <span class="n">α</span><span class="o">]</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="o">:</span> <span class="n">α</span> <span class="o">:=</span> <span class="n">a</span> <span class="bp">⋄</span> <span class="n">b</span> </pre></div> </div> <p>Note this syntax is also available in the <code class="docutils literal notranslate"><span class="pre">structure</span></code> command, although it that case it fixes only the hurdle of writing fields such as <cite>toDia₁</cite> since there is no instance to define in that case.</p> <p>Let us now try to combine a diamond operation and a distinguished one with axioms saying this element is neutral on both sides.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">DiaOneClass₁</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">One₁</span> <span class="n">α</span><span class="o">,</span> <span class="n">Dia₁</span> <span class="n">α</span> <span class="n">where</span> <span class="sd">/-- One is a left neutral element for diamond. -/</span> <span class="n">one_dia</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="mi">𝟙</span> <span class="bp">⋄</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">a</span> <span class="sd">/-- One is a right neutral element for diamond -/</span> <span class="n">dia_one</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">a</span> <span class="bp">⋄</span> <span class="mi">𝟙</span> <span class="bp">=</span> <span class="n">a</span> </pre></div> </div> <p>In the next example, we tell Lean that <code class="docutils literal notranslate"><span class="pre">α</span></code> has a <code class="docutils literal notranslate"><span class="pre">DiaOneClass₁</span></code> structure and state a property that uses both a <cite>Dia₁</cite> instance and a <cite>One₁</cite> instance. In order to see how Lean finds those instances we set a tracing option whose result can be seen in the info view. This result is rather terse by default but can be expended by clicking one lines ending with black arrows. It includes failed attempts where Lean tried to find instances before having enough type information to succceed. The successful attempts do involve the instances generated by the <code class="docutils literal notranslate"><span class="pre">extends</span></code> syntax.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">set_option</span> <span class="n">trace.Meta.synthInstance</span> <span class="n">true</span> <span class="k">in</span> <span class="kd">example</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">}</span> <span class="o">[</span><span class="n">DiaOneClass₁</span> <span class="n">α</span><span class="o">]</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">α</span><span class="o">)</span> <span class="o">:</span> <span class="kt">Prop</span> <span class="o">:=</span> <span class="n">a</span> <span class="bp">⋄</span> <span class="n">b</span> <span class="bp">=</span> <span class="mi">𝟙</span> </pre></div> </div> <p>Note that we don’t need to include extra fields where combining existing classes. Hence we can define monoids as:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">Monoid₁</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">Semigroup₁</span> <span class="n">α</span><span class="o">,</span> <span class="n">DiaOneClass₁</span> <span class="n">α</span> </pre></div> </div> <p>While the above definition seems straightforward, it hides an important subtlety. Both <code class="docutils literal notranslate"><span class="pre">Semigroup₁</span> <span class="pre">α</span></code> and <code class="docutils literal notranslate"><span class="pre">DiaOneClass₁</span> <span class="pre">α</span></code> extend <code class="docutils literal notranslate"><span class="pre">Dia₁</span> <span class="pre">α</span></code>, so one could fear that having a <code class="docutils literal notranslate"><span class="pre">Monoid₁</span> <span class="pre">α</span></code> instance gives two unrelated diamond operations on <code class="docutils literal notranslate"><span class="pre">α</span></code>, one coming from a field <code class="docutils literal notranslate"><span class="pre">Monoid₁.toSemigroup₁</span></code> and one coming from a field <code class="docutils literal notranslate"><span class="pre">Monoid₁.toDiaOneClass₁</span></code>.</p> <p>Indeed if we try to build a monoid class by hand using:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">Monoid₂</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="n">where</span> <span class="n">toSemigroup₁</span> <span class="o">:</span> <span class="n">Semigroup₁</span> <span class="n">α</span> <span class="n">toDiaOneClass₁</span> <span class="o">:</span> <span class="n">DiaOneClass₁</span> <span class="n">α</span> </pre></div> </div> <p>then we get two completely unrelated diamond operations <code class="docutils literal notranslate"><span class="pre">Monoid₂.toSemigroup₁.toDia₁.dia</span></code> and <code class="docutils literal notranslate"><span class="pre">Monoid₂.toDiaOneClass₁.toDia₁.dia</span></code>.</p> <p>The version generated using the <code class="docutils literal notranslate"><span class="pre">extends</span></code> syntax does not have this defect.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">}</span> <span class="o">[</span><span class="n">Monoid₁</span> <span class="n">α</span><span class="o">]</span> <span class="o">:</span> <span class="o">(</span><span class="n">Monoid₁.toSemigroup₁.toDia₁.dia</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">α</span><span class="o">)</span> <span class="bp">=</span> <span class="n">Monoid₁.toDiaOneClass₁.toDia₁.dia</span> <span class="o">:=</span> <span class="n">rfl</span> </pre></div> </div> <p>So the <code class="docutils literal notranslate"><span class="pre">class</span></code> command did some magic for us (and the <code class="docutils literal notranslate"><span class="pre">structure</span></code> command would have done it too). An easy way to see what are the fields of our classes is to check their constructor. Compare:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="c">/-</span><span class="cm"> Monoid₂.mk {α : Type} (toSemigroup₁ : Semigroup₁ α) (toDiaOneClass₁ : DiaOneClass₁ α) : Monoid₂ α -/</span> <span class="k">#check</span> <span class="n">Monoid₂.mk</span> <span class="c">/-</span><span class="cm"> Monoid₁.mk {α : Type} [toSemigroup₁ : Semigroup₁ α] [toOne₁ : One₁ α] (one_dia : ∀ (a : α), 𝟙 ⋄ a = a) (dia_one : ∀ (a : α), a ⋄ 𝟙 = a) : Monoid₁ α -/</span> <span class="k">#check</span> <span class="n">Monoid₁.mk</span> </pre></div> </div> <p>So we see that <code class="docutils literal notranslate"><span class="pre">Monoid₁</span></code> takes <code class="docutils literal notranslate"><span class="pre">Semigroup₁</span> <span class="pre">α</span></code> argument as expected but then it won’t take a would-be overlapping <code class="docutils literal notranslate"><span class="pre">DiaOneClass₁</span> <span class="pre">α</span></code> argument but instead tears it appart and includes only the non-overlapping parts. And it also auto-generated an instance <code class="docutils literal notranslate"><span class="pre">Monoid₁.toDiaOneClass₁</span></code> which is <em>not</em> a field but has the expected signature which, from the end-user point of view, restores the symmetry between the two extended classes <code class="docutils literal notranslate"><span class="pre">Semigroup₁</span></code> and <code class="docutils literal notranslate"><span class="pre">DiaOneClass₁</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="n">Monoid₁.toSemigroup₁</span> <span class="k">#check</span> <span class="n">Monoid₁.toDiaOneClass₁</span> </pre></div> </div> <p>We are now very close to defining groups. We could add to the monoid structure a field asserting the existence of an inverse for every element. But then we would need to work to access these inverses. In practice it is more convenient to add it as data. To optimize reusability, we define a new data-carrying class, and then give it some notation.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">Inv₁</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="n">where</span> <span class="sd">/-- The inversion function -/</span> <span class="n">inv</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">α</span> <span class="kd">@[inherit_doc]</span> <span class="kd">postfix</span><span class="o">:</span><span class="n">max</span> <span class="s2">"⁻¹"</span> <span class="bp">=></span> <span class="n">Inv₁.inv</span> <span class="kd">class</span> <span class="n">Group₁</span> <span class="o">(</span><span class="n">G</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">Monoid₁</span> <span class="n">G</span><span class="o">,</span> <span class="n">Inv</span> <span class="n">G</span> <span class="n">where</span> <span class="n">inv_dia</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">G</span><span class="o">,</span> <span class="n">a</span><span class="bp">⁻¹</span> <span class="bp">⋄</span> <span class="n">a</span> <span class="bp">=</span> <span class="mi">𝟙</span> </pre></div> </div> <p>The above definition may seem too weak, we only ask that <code class="docutils literal notranslate"><span class="pre">a⁻¹</span></code> is a left-inverse of <code class="docutils literal notranslate"><span class="pre">a</span></code>. But the other side is automatic. In order to prove that, we need a preliminary lemma.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">lemma</span> <span class="n">left_inv_eq_right_inv₁</span> <span class="o">{</span><span class="n">M</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">}</span> <span class="o">[</span><span class="n">Monoid₁</span> <span class="n">M</span><span class="o">]</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">M</span><span class="o">}</span> <span class="o">(</span><span class="n">hba</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">⋄</span> <span class="n">a</span> <span class="bp">=</span> <span class="mi">𝟙</span><span class="o">)</span> <span class="o">(</span><span class="n">hac</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">⋄</span> <span class="n">c</span> <span class="bp">=</span> <span class="mi">𝟙</span><span class="o">)</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">c</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="bp">←</span> <span class="n">DiaOneClass₁.one_dia</span> <span class="n">c</span><span class="o">,</span> <span class="bp">←</span> <span class="n">hba</span><span class="o">,</span> <span class="n">Semigroup₁.dia_assoc</span><span class="o">,</span> <span class="n">hac</span><span class="o">,</span> <span class="n">DiaOneClass₁.dia_one</span> <span class="n">b</span><span class="o">]</span> </pre></div> </div> <p>In this lemma, it is pretty annoying to give full names, especially since it requires knowing which part of the hierarchy provides those facts. One way to fix this is to use the <code class="docutils literal notranslate"><span class="pre">export</span></code> command to copy those facts as lemmas in the root name space.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">export</span> <span class="n">DiaOneClass₁</span> <span class="o">(</span><span class="n">one_dia</span> <span class="n">dia_one</span><span class="o">)</span> <span class="kn">export</span> <span class="n">Semigroup₁</span> <span class="o">(</span><span class="n">dia_assoc</span><span class="o">)</span> <span class="kn">export</span> <span class="n">Group₁</span> <span class="o">(</span><span class="n">inv_dia</span><span class="o">)</span> </pre></div> </div> <p>We can then rewrite the above proof as:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">M</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">}</span> <span class="o">[</span><span class="n">Monoid₁</span> <span class="n">M</span><span class="o">]</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">M</span><span class="o">}</span> <span class="o">(</span><span class="n">hba</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">⋄</span> <span class="n">a</span> <span class="bp">=</span> <span class="mi">𝟙</span><span class="o">)</span> <span class="o">(</span><span class="n">hac</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">⋄</span> <span class="n">c</span> <span class="bp">=</span> <span class="mi">𝟙</span><span class="o">)</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">c</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="bp">←</span> <span class="n">one_dia</span> <span class="n">c</span><span class="o">,</span> <span class="bp">←</span> <span class="n">hba</span><span class="o">,</span> <span class="n">dia_assoc</span><span class="o">,</span> <span class="n">hac</span><span class="o">,</span> <span class="n">dia_one</span> <span class="n">b</span><span class="o">]</span> </pre></div> </div> <p>It is now your turn to prove things about our algebraic structures.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">lemma</span> <span class="n">inv_eq_of_dia</span> <span class="o">[</span><span class="n">Group₁</span> <span class="n">G</span><span class="o">]</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">G</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">⋄</span> <span class="n">b</span> <span class="bp">=</span> <span class="mi">𝟙</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span><span class="bp">⁻¹</span> <span class="bp">=</span> <span class="n">b</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="kd">lemma</span> <span class="n">dia_inv</span> <span class="o">[</span><span class="n">Group₁</span> <span class="n">G</span><span class="o">]</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">G</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">⋄</span> <span class="n">a</span><span class="bp">⁻¹</span> <span class="bp">=</span> <span class="mi">𝟙</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>At this stage we would like to move on to define rings, but there is a serious issue. A ring structure on a type contains both an additive group structure and a multiplicative monoid structure, and some properties about their interaction. But so far we hard-coded a notation <code class="docutils literal notranslate"><span class="pre">⋄</span></code> for all our operations. More fundamentally, the type class system assumes every type has only one instance of each type class. There are various ways to solve this issue. Surprisingly mathlib uses the naive idea to duplicate everything for additive and multiplicative theories with the help of some code-generating attribute. Structures and classes are defined in both additive and multiplicative notation with an attibute <code class="docutils literal notranslate"><span class="pre">to_additive</span></code> linking them. In case of multiple inheritance like for semi-groups, the auto-generated “symmetry-restoring” instances need also to be marked. This is a bit technical you don’t need to understand details. The important point is that lemmas are then only stated in multiplicative notation and marked with the attribute <code class="docutils literal notranslate"><span class="pre">to_additive</span></code> to generate the additive version as <code class="docutils literal notranslate"><span class="pre">left_inv_eq_right_inv'</span></code> with it’s auto-generated additive version <code class="docutils literal notranslate"><span class="pre">left_neg_eq_right_neg'</span></code>. In order to check the name of this additive version we used the <code class="docutils literal notranslate"><span class="pre">whatsnew</span> <span class="pre">in</span></code> command on top of <code class="docutils literal notranslate"><span class="pre">left_inv_eq_right_inv'</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">AddSemigroup₃</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">Add</span> <span class="n">α</span> <span class="n">where</span> <span class="sd">/-- Multiplication is associative -/</span> <span class="n">add_assoc₃</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">+</span> <span class="o">(</span><span class="n">b</span> <span class="bp">+</span> <span class="n">c</span><span class="o">)</span> <span class="kd">@[to_additive AddSemigroup₃]</span> <span class="kd">class</span> <span class="n">Semigroup₃</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">Mul</span> <span class="n">α</span> <span class="n">where</span> <span class="sd">/-- Multiplication is associative -/</span> <span class="n">mul_assoc₃</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="o">(</span><span class="n">b</span> <span class="bp">*</span> <span class="n">c</span><span class="o">)</span> <span class="kd">class</span> <span class="n">AddMonoid₃</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">AddSemigroup₃</span> <span class="n">α</span><span class="o">,</span> <span class="n">AddZeroClass</span> <span class="n">α</span> <span class="kd">@[to_additive AddMonoid₃]</span> <span class="kd">class</span> <span class="n">Monoid₃</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">Semigroup₃</span> <span class="n">α</span><span class="o">,</span> <span class="n">MulOneClass</span> <span class="n">α</span> <span class="kn">attribute</span> <span class="o">[</span><span class="n">to_additive</span> <span class="n">existing</span><span class="o">]</span> <span class="n">Monoid₃.toMulOneClass</span> <span class="kn">export</span> <span class="n">Semigroup₃</span> <span class="o">(</span><span class="n">mul_assoc₃</span><span class="o">)</span> <span class="kn">export</span> <span class="n">AddSemigroup₃</span> <span class="o">(</span><span class="n">add_assoc₃</span><span class="o">)</span> <span class="n">whatsnew</span> <span class="k">in</span> <span class="kd">@[to_additive]</span> <span class="kd">lemma</span> <span class="n">left_inv_eq_right_inv'</span> <span class="o">{</span><span class="n">M</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">}</span> <span class="o">[</span><span class="n">Monoid₃</span> <span class="n">M</span><span class="o">]</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">M</span><span class="o">}</span> <span class="o">(</span><span class="n">hba</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">=</span> <span class="mi">1</span><span class="o">)</span> <span class="o">(</span><span class="n">hac</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">=</span> <span class="mi">1</span><span class="o">)</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">c</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="bp">←</span> <span class="n">one_mul</span> <span class="n">c</span><span class="o">,</span> <span class="bp">←</span> <span class="n">hba</span><span class="o">,</span> <span class="n">mul_assoc₃</span><span class="o">,</span> <span class="n">hac</span><span class="o">,</span> <span class="n">mul_one</span> <span class="n">b</span><span class="o">]</span> <span class="k">#check</span> <span class="n">left_neg_eq_right_neg'</span> </pre></div> </div> <p>Equipped with this technology, we can easily define also commutative semigroups, monoids and groups, and then define rings.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">AddCommSemigroup₃</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">AddSemigroup₃</span> <span class="n">α</span> <span class="n">where</span> <span class="n">add_comm</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">a</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">a</span> <span class="kd">@[to_additive AddCommSemigroup₃]</span> <span class="kd">class</span> <span class="n">CommSemigroup₃</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">Semigroup₃</span> <span class="n">α</span> <span class="n">where</span> <span class="n">mul_comm</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">a</span> <span class="kd">class</span> <span class="n">AddCommMonoid₃</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">AddMonoid₃</span> <span class="n">α</span><span class="o">,</span> <span class="n">AddCommSemigroup₃</span> <span class="n">α</span> <span class="kd">@[to_additive AddCommMonoid₃]</span> <span class="kd">class</span> <span class="n">CommMonoid₃</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">Monoid₃</span> <span class="n">α</span><span class="o">,</span> <span class="n">CommSemigroup₃</span> <span class="n">α</span> <span class="kd">class</span> <span class="n">AddGroup₃</span> <span class="o">(</span><span class="n">G</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">AddMonoid₃</span> <span class="n">G</span><span class="o">,</span> <span class="n">Neg</span> <span class="n">G</span> <span class="n">where</span> <span class="n">neg_add</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">G</span><span class="o">,</span> <span class="bp">-</span><span class="n">a</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">=</span> <span class="mi">0</span> <span class="kd">@[to_additive AddGroup₃]</span> <span class="kd">class</span> <span class="n">Group₃</span> <span class="o">(</span><span class="n">G</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">Monoid₃</span> <span class="n">G</span><span class="o">,</span> <span class="n">Inv</span> <span class="n">G</span> <span class="n">where</span> <span class="n">inv_mul</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">G</span><span class="o">,</span> <span class="n">a</span><span class="bp">⁻¹</span> <span class="bp">*</span> <span class="n">a</span> <span class="bp">=</span> <span class="mi">1</span> </pre></div> </div> <p>We should remember to tagged lemmas with <code class="docutils literal notranslate"><span class="pre">simp</span></code> when approriate.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">attribute</span> <span class="o">[</span><span class="n">simp</span><span class="o">]</span> <span class="n">Group₃.inv_mul</span> <span class="n">AddGroup₃.neg_add</span> </pre></div> </div> <p>Then we need to repeat ourselves a bit since we switch to standard notations, but at least <code class="docutils literal notranslate"><span class="pre">to_additive</span></code> does the work of translating from the multiplicative notation to the additive one.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">@[to_additive]</span> <span class="kd">lemma</span> <span class="n">inv_eq_of_mul</span> <span class="o">[</span><span class="n">Group₃</span> <span class="n">G</span><span class="o">]</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">G</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">=</span> <span class="mi">1</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span><span class="bp">⁻¹</span> <span class="bp">=</span> <span class="n">b</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>Note that <code class="docutils literal notranslate"><span class="pre">to_additive</span></code> can be ask to tag a lemma with <code class="docutils literal notranslate"><span class="pre">simp</span></code> and propagate that attribute to the additive version as follows.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">@[to_additive (attr := simp)]</span> <span class="kd">lemma</span> <span class="n">Group₃.mul_inv</span> <span class="o">{</span><span class="n">G</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">}</span> <span class="o">[</span><span class="n">Group₃</span> <span class="n">G</span><span class="o">]</span> <span class="o">{</span><span class="n">a</span> <span class="o">:</span> <span class="n">G</span><span class="o">}</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">a</span><span class="bp">⁻¹</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">@[to_additive]</span> <span class="kd">lemma</span> <span class="n">mul_left_cancel₃</span> <span class="o">{</span><span class="n">G</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">}</span> <span class="o">[</span><span class="n">Group₃</span> <span class="n">G</span><span class="o">]</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">G</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">c</span><span class="o">)</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">c</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">@[to_additive]</span> <span class="kd">lemma</span> <span class="n">mul_right_cancel₃</span> <span class="o">{</span><span class="n">G</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">}</span> <span class="o">[</span><span class="n">Group₃</span> <span class="n">G</span><span class="o">]</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">G</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">b</span><span class="bp">*</span><span class="n">a</span> <span class="bp">=</span> <span class="n">c</span><span class="bp">*</span><span class="n">a</span><span class="o">)</span> <span class="o">:</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">c</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="kd">class</span> <span class="n">AddCommGroup₃</span> <span class="o">(</span><span class="n">G</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">AddGroup₃</span> <span class="n">G</span><span class="o">,</span> <span class="n">AddCommMonoid₃</span> <span class="n">G</span> <span class="kd">@[to_additive AddCommGroup₃]</span> <span class="kd">class</span> <span class="n">CommGroup₃</span> <span class="o">(</span><span class="n">G</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">Group₃</span> <span class="n">G</span><span class="o">,</span> <span class="n">CommMonoid₃</span> <span class="n">G</span> </pre></div> </div> <p>We are now ready for rings. For demonstration puprposes we won’t assume that addition is commutative, and then immediately provide an instance of <code class="docutils literal notranslate"><span class="pre">AddCommGroup₃</span></code>. Mathlib does not play this game, first because in practice this does not make any ring instance easier and also because Mathlib’s algebraic hierarchy goes through semi-rings which are like rings but without opposites so that the proof below does not work for them. What we gain here, besides a nice exercise if you have never seen it, is an example of building an instance using the syntax that allows to provide a parent structure and some extra fields.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">Ring₃</span> <span class="o">(</span><span class="n">R</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">AddGroup₃</span> <span class="n">R</span><span class="o">,</span> <span class="n">Monoid₃</span> <span class="n">R</span><span class="o">,</span> <span class="n">MulZeroClass</span> <span class="n">R</span> <span class="n">where</span> <span class="sd">/-- Multiplication is left distributive over addition -/</span> <span class="n">left_distrib</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">R</span><span class="o">,</span> <span class="n">a</span> <span class="bp">*</span> <span class="o">(</span><span class="n">b</span> <span class="bp">+</span> <span class="n">c</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">c</span> <span class="sd">/-- Multiplication is right distributive over addition -/</span> <span class="n">right_distrib</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">R</span><span class="o">,</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">c</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">*</span> <span class="n">c</span> <span class="kd">instance</span> <span class="o">{</span><span class="n">R</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">}</span> <span class="o">[</span><span class="n">Ring₃</span> <span class="n">R</span><span class="o">]</span> <span class="o">:</span> <span class="n">AddCommGroup₃</span> <span class="n">R</span> <span class="o">:=</span> <span class="o">{</span> <span class="n">Ring₃.toAddGroup₃</span> <span class="k">with</span> <span class="n">add_comm</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="o">}</span> </pre></div> </div> <p>Of course we can also build concrete instances, such as a ring structure on integers (of course the instance below uses that all the work is already done in Mathlib).</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="o">:</span> <span class="n">Ring₃</span> <span class="n">ℤ</span> <span class="n">where</span> <span class="n">add</span> <span class="o">:=</span> <span class="o">(</span><span class="bp">·</span> <span class="bp">+</span> <span class="bp">·</span><span class="o">)</span> <span class="n">add_assoc₃</span> <span class="o">:=</span> <span class="n">add_assoc</span> <span class="n">zero</span> <span class="o">:=</span> <span class="mi">0</span> <span class="n">zero_add</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="n">add_zero</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="n">neg</span> <span class="o">:=</span> <span class="o">(</span><span class="bp">-</span> <span class="bp">·</span><span class="o">)</span> <span class="n">neg_add</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="n">mul</span> <span class="o">:=</span> <span class="o">(</span><span class="bp">·</span> <span class="bp">*</span> <span class="bp">·</span><span class="o">)</span> <span class="n">mul_assoc₃</span> <span class="o">:=</span> <span class="n">mul_assoc</span> <span class="n">one</span> <span class="o">:=</span> <span class="mi">1</span> <span class="n">one_mul</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="n">mul_one</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="n">zero_mul</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="n">mul_zero</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="n">left_distrib</span> <span class="o">:=</span> <span class="n">Int.mul_add</span> <span class="n">right_distrib</span> <span class="o">:=</span> <span class="n">Int.add_mul</span> </pre></div> </div> <p>As an exercise you can now set up a simple hierarchy for order relations, including a class for ordered commutative monoids, which have both a partial order and a commutative monoid structure such that <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">a</span> <span class="pre">b</span> <span class="pre">:</span> <span class="pre">α,</span> <span class="pre">a</span> <span class="pre">≤</span> <span class="pre">b</span> <span class="pre">→</span> <span class="pre">∀</span> <span class="pre">c</span> <span class="pre">:</span> <span class="pre">α,</span> <span class="pre">c</span> <span class="pre">*</span> <span class="pre">a</span> <span class="pre">≤</span> <span class="pre">c</span> <span class="pre">*</span> <span class="pre">b</span></code>. Of course you need to add fields and maybe <code class="docutils literal notranslate"><span class="pre">extends</span></code> clauses to the following classes.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">LE₁</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="n">where</span> <span class="sd">/-- The Less-or-Equal relation. -/</span> <span class="n">le</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">α</span> <span class="bp">→</span> <span class="kt">Prop</span> <span class="kd">@[inherit_doc]</span> <span class="kd">infix</span><span class="o">:</span><span class="mi">50</span> <span class="s2">" ≤₁ "</span> <span class="bp">=></span> <span class="n">LE₁.le</span> <span class="kd">class</span> <span class="n">Preorder₁</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">class</span> <span class="n">PartialOrder₁</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">class</span> <span class="n">OrderedCommMonoid₁</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">instance</span> <span class="o">:</span> <span class="n">OrderedCommMonoid₁</span> <span class="n">ℕ</span> <span class="n">where</span> </pre></div> </div> <p>We now want to discuss algebraic structures involving several types. The prime example is modules over rings. If you don’t know what is a module, you can pretend it means vector space and think that all our rings are fields. Those structures are commutative additive groups equipped with a scalar multiplication by elements of some ring.</p> <p>We first define the data-carrying type class of scalar multiplication by some type <code class="docutils literal notranslate"><span class="pre">α</span></code> on some type <code class="docutils literal notranslate"><span class="pre">β</span></code>, and give it a right associative notation.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">SMul₃</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">(</span><span class="n">β</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="n">where</span> <span class="sd">/-- Scalar multiplication -/</span> <span class="n">smul</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">β</span> <span class="bp">→</span> <span class="n">β</span> <span class="kd">infixr</span><span class="o">:</span><span class="mi">73</span> <span class="s2">" • "</span> <span class="bp">=></span> <span class="n">SMul₃.smul</span> </pre></div> </div> <p>Then we can define modules (again think about vector spaces if you don’t know what is a module).</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">Module₁</span> <span class="o">(</span><span class="n">R</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">Ring₃</span> <span class="n">R</span><span class="o">]</span> <span class="o">(</span><span class="n">M</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">AddCommGroup₃</span> <span class="n">M</span><span class="o">]</span> <span class="kd">extends</span> <span class="n">SMul₃</span> <span class="n">R</span> <span class="n">M</span> <span class="n">where</span> <span class="n">zero_smul</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">m</span> <span class="o">:</span> <span class="n">M</span><span class="o">,</span> <span class="o">(</span><span class="mi">0</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="bp">•</span> <span class="n">m</span> <span class="bp">=</span> <span class="mi">0</span> <span class="n">one_smul</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">m</span> <span class="o">:</span> <span class="n">M</span><span class="o">,</span> <span class="o">(</span><span class="mi">1</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="bp">•</span> <span class="n">m</span> <span class="bp">=</span> <span class="n">m</span> <span class="n">mul_smul</span> <span class="o">:</span> <span class="bp">∀</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="o">(</span><span class="n">m</span> <span class="o">:</span> <span class="n">M</span><span class="o">),</span> <span class="o">(</span><span class="n">a</span> <span class="bp">*</span> <span class="n">b</span><span class="o">)</span> <span class="bp">•</span> <span class="n">m</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">•</span> <span class="n">b</span> <span class="bp">•</span> <span class="n">m</span> <span class="n">add_smul</span> <span class="o">:</span> <span class="bp">∀</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="o">(</span><span class="n">m</span> <span class="o">:</span> <span class="n">M</span><span class="o">),</span> <span class="o">(</span><span class="n">a</span> <span class="bp">+</span> <span class="n">b</span><span class="o">)</span> <span class="bp">•</span> <span class="n">m</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">•</span> <span class="n">m</span> <span class="bp">+</span> <span class="n">b</span> <span class="bp">•</span> <span class="n">m</span> <span class="n">smul_add</span> <span class="o">:</span> <span class="bp">∀</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">R</span><span class="o">)</span> <span class="o">(</span><span class="n">m</span> <span class="n">n</span> <span class="o">:</span> <span class="n">M</span><span class="o">),</span> <span class="n">a</span> <span class="bp">•</span> <span class="o">(</span><span class="n">m</span> <span class="bp">+</span> <span class="n">n</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">•</span> <span class="n">m</span> <span class="bp">+</span> <span class="n">a</span> <span class="bp">•</span> <span class="n">n</span> </pre></div> </div> <p>There is something interesting going on here. While it isn’t too surprising that the ring structure on <code class="docutils literal notranslate"><span class="pre">R</span></code> is a parameter in this definition, you probably expected <code class="docutils literal notranslate"><span class="pre">AddCommGroup3</span> <span class="pre">M</span></code> to be part of the <code class="docutils literal notranslate"><span class="pre">extends</span></code> clause just as <code class="docutils literal notranslate"><span class="pre">SMul₃</span> <span class="pre">R</span> <span class="pre">M</span></code> is. Trying to do that would lead to a mysterious sounding error message: <code class="docutils literal notranslate"><span class="pre">cannot</span> <span class="pre">find</span> <span class="pre">synthesization</span> <span class="pre">order</span> <span class="pre">for</span> <span class="pre">instance</span> <span class="pre">Module₁.toAddCommGroup₃</span> <span class="pre">with</span> <span class="pre">type</span> <span class="pre">(R</span> <span class="pre">:</span> <span class="pre">Type)</span> <span class="pre">→</span> <span class="pre">[inst</span> <span class="pre">:</span> <span class="pre">Ring₃</span> <span class="pre">R]</span> <span class="pre">→</span> <span class="pre">{M</span> <span class="pre">:</span> <span class="pre">Type}</span> <span class="pre">→</span> <span class="pre">[self</span> <span class="pre">:</span> <span class="pre">Module₁</span> <span class="pre">R</span> <span class="pre">M]</span> <span class="pre">→</span> <span class="pre">AddCommGroup₃</span> <span class="pre">M</span> <span class="pre">all</span> <span class="pre">remaining</span> <span class="pre">arguments</span> <span class="pre">have</span> <span class="pre">metavariables:</span> <span class="pre">Ring₃</span> <span class="pre">?R</span> <span class="pre">@Module₁</span> <span class="pre">?R</span> <span class="pre">?inst✝</span> <span class="pre">M</span></code>. In order to understand this message, you need to remember that such an <code class="docutils literal notranslate"><span class="pre">extends</span></code> clause would lead to a field <code class="docutils literal notranslate"><span class="pre">Module₃.toAddCommGroup₃</span></code> marked as an instance. This instance would have the signature appearing in the error message: <code class="docutils literal notranslate"><span class="pre">(R</span> <span class="pre">:</span> <span class="pre">Type)</span> <span class="pre">→</span> <span class="pre">[inst</span> <span class="pre">:</span> <span class="pre">Ring₃</span> <span class="pre">R]</span> <span class="pre">→</span> <span class="pre">{M</span> <span class="pre">:</span> <span class="pre">Type}</span> <span class="pre">→</span> <span class="pre">[self</span> <span class="pre">:</span> <span class="pre">Module₁</span> <span class="pre">R</span> <span class="pre">M]</span> <span class="pre">→</span> <span class="pre">AddCommGroup₃</span> <span class="pre">M</span></code>. With such an instance in the type class database, each time Lean would look for a <code class="docutils literal notranslate"><span class="pre">AddCommGroup₃</span> <span class="pre">M</span></code> instance for some <code class="docutils literal notranslate"><span class="pre">M</span></code>, it would need to go hunting for a completely unspecified type <code class="docutils literal notranslate"><span class="pre">R``and</span> <span class="pre">a</span> <span class="pre">``Ring₃</span> <span class="pre">R</span></code> instance before embarking on the main quest of finding a <code class="docutils literal notranslate"><span class="pre">Module₁</span> <span class="pre">R</span> <span class="pre">M</span></code> instance. Those two side-quests are represented by the meta-variables mentionned in the error message and denoted by <code class="docutils literal notranslate"><span class="pre">?R</span></code> and <code class="docutils literal notranslate"><span class="pre">?inst✝</span></code> there. Such a <code class="docutils literal notranslate"><span class="pre">Module₃.toAddCommGroup₃</span></code> instance would then be a huge trap for the instance resolution procedure and then <code class="docutils literal notranslate"><span class="pre">class</span></code> command refuses to set it up.</p> <p>What about <code class="docutils literal notranslate"><span class="pre">extends</span> <span class="pre">SMul₃</span> <span class="pre">R</span> <span class="pre">M</span></code> then? That one creates a field <code class="docutils literal notranslate"><span class="pre">Module₁.toSMul₃</span> <span class="pre">:</span> <span class="pre">{R</span> <span class="pre">:</span> <span class="pre">Type}</span> <span class="pre">→</span>  <span class="pre">[inst</span> <span class="pre">:</span> <span class="pre">Ring₃</span> <span class="pre">R]</span> <span class="pre">→</span> <span class="pre">{M</span> <span class="pre">:</span> <span class="pre">Type}</span> <span class="pre">→</span> <span class="pre">[inst_1</span> <span class="pre">:</span> <span class="pre">AddCommGroup₃</span> <span class="pre">M]</span> <span class="pre">→</span> <span class="pre">[self</span> <span class="pre">:</span> <span class="pre">Module₁</span> <span class="pre">R</span> <span class="pre">M]</span> <span class="pre">→</span> <span class="pre">SMul₃</span> <span class="pre">R</span> <span class="pre">M</span></code> whose end result <code class="docutils literal notranslate"><span class="pre">SMul₃</span> <span class="pre">R</span> <span class="pre">M</span></code> mentions both <code class="docutils literal notranslate"><span class="pre">R</span></code> and <code class="docutils literal notranslate"><span class="pre">M</span></code> so this field can safely be used as an instance. The rule is easy to remember: each class appearing in the <code class="docutils literal notranslate"><span class="pre">extends</span></code> clause should mention every type appearing in the parameters.</p> <p>Let us create our first module instance: a ring is a module over itself using its multiplication as a scalar multiplication.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="n">selfModule</span> <span class="o">(</span><span class="n">R</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">Ring₃</span> <span class="n">R</span><span class="o">]</span> <span class="o">:</span> <span class="n">Module₁</span> <span class="n">R</span> <span class="n">R</span> <span class="n">where</span> <span class="n">smul</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">r</span> <span class="n">s</span> <span class="bp">↦</span> <span class="n">r</span><span class="bp">*</span><span class="n">s</span> <span class="n">zero_smul</span> <span class="o">:=</span> <span class="n">zero_mul</span> <span class="n">one_smul</span> <span class="o">:=</span> <span class="n">one_mul</span> <span class="n">mul_smul</span> <span class="o">:=</span> <span class="n">mul_assoc₃</span> <span class="n">add_smul</span> <span class="o">:=</span> <span class="n">Ring₃.right_distrib</span> <span class="n">smul_add</span> <span class="o">:=</span> <span class="n">Ring₃.left_distrib</span> </pre></div> </div> <p>As a second example, every abelian group is a module over <code class="docutils literal notranslate"><span class="pre">ℤ</span></code> (this is one of the reason to generalize the theory of vector spaces by allowing non-invertible scalars). First one can define scalar multiplication by a natural number for any type equipped with a zero and an addition: <code class="docutils literal notranslate"><span class="pre">n</span> <span class="pre">•</span> <span class="pre">a</span></code> is defined as <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">+</span> <span class="pre">⋯</span> <span class="pre">+</span> <span class="pre">a</span></code> where <code class="docutils literal notranslate"><span class="pre">a</span></code> appears <code class="docutils literal notranslate"><span class="pre">n</span></code> times. Then this is extended to scalar multiplication by an integer by ensuring <code class="docutils literal notranslate"><span class="pre">(-1)</span> <span class="pre">•</span> <span class="pre">a</span> <span class="pre">=</span> <span class="pre">-a</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">nsmul₁</span> <span class="o">[</span><span class="n">Zero</span> <span class="n">M</span><span class="o">]</span> <span class="o">[</span><span class="n">Add</span> <span class="n">M</span><span class="o">]</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">M</span> <span class="bp">→</span> <span class="n">M</span> <span class="bp">|</span> <span class="mi">0</span><span class="o">,</span> <span class="n">_</span> <span class="bp">=></span> <span class="mi">0</span> <span class="bp">|</span> <span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">,</span> <span class="n">a</span> <span class="bp">=></span> <span class="n">a</span> <span class="bp">+</span> <span class="n">nsmul₁</span> <span class="n">n</span> <span class="n">a</span> <span class="kd">def</span> <span class="n">zsmul₁</span> <span class="o">{</span><span class="n">M</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">Zero</span> <span class="n">M</span><span class="o">]</span> <span class="o">[</span><span class="n">Add</span> <span class="n">M</span><span class="o">]</span> <span class="o">[</span><span class="n">Neg</span> <span class="n">M</span><span class="o">]</span> <span class="o">:</span> <span class="n">ℤ</span> <span class="bp">→</span> <span class="n">M</span> <span class="bp">→</span> <span class="n">M</span> <span class="bp">|</span> <span class="n">Int.ofNat</span> <span class="n">n</span><span class="o">,</span> <span class="n">a</span> <span class="bp">=></span> <span class="n">nsmul₁</span> <span class="n">n</span> <span class="n">a</span> <span class="bp">|</span> <span class="n">Int.negSucc</span> <span class="n">n</span><span class="o">,</span> <span class="n">a</span> <span class="bp">=></span> <span class="bp">-</span><span class="n">nsmul₁</span> <span class="n">n.succ</span> <span class="n">a</span> </pre></div> </div> <p>Proving this gives rise to a module structure is a bit tedious and not interesting for the current discussion, so we will sorry all axioms. You are <em>not</em> asked to replace those sorries with proofs. If you insist on doing it then you will probably want to state and prove several intermediate lemmas about <code class="docutils literal notranslate"><span class="pre">nsmul₁</span></code> and <code class="docutils literal notranslate"><span class="pre">zsmul₁</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="n">abGrpModule</span> <span class="o">(</span><span class="n">A</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">AddCommGroup₃</span> <span class="n">A</span><span class="o">]</span> <span class="o">:</span> <span class="n">Module₁</span> <span class="n">ℤ</span> <span class="n">A</span> <span class="n">where</span> <span class="n">smul</span> <span class="o">:=</span> <span class="n">zsmul₁</span> <span class="n">zero_smul</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">one_smul</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">mul_smul</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">add_smul</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">smul_add</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>A much more important issue is that we now have two module structures over the ring <code class="docutils literal notranslate"><span class="pre">ℤ</span></code> for <code class="docutils literal notranslate"><span class="pre">ℤ</span></code> itself: <code class="docutils literal notranslate"><span class="pre">abGrpModule</span> <span class="pre">ℤ</span></code> since <code class="docutils literal notranslate"><span class="pre">ℤ</span></code> is a abelian group, and <code class="docutils literal notranslate"><span class="pre">selfModule</span> <span class="pre">ℤ</span></code> since <code class="docutils literal notranslate"><span class="pre">ℤ</span></code> is a ring. Those two module structure correspond to the same abelian group structure, but it is not obvious that they have the same scalar multiplication. They actually do, but this isn’t true by definition, it requires a proof. This is very bad news for the type class instance resolution procedure and will lead to very frustating failures for users of this hierarchy. When directly asked to find an instance, Lean will pick one, and we can see which one using:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="bp">#</span><span class="n">synth</span> <span class="n">Module₁</span> <span class="n">ℤ</span> <span class="n">ℤ</span> <span class="c1">-- abGrpModule ℤ</span> </pre></div> </div> <p>But in a more indirect context it can happen that Lean infers the one and then gets confused. This situation is known as a bad diamond. This has nothing to do with the diamond operation we used above, it refers to the way one can draw the paths from <code class="docutils literal notranslate"><span class="pre">ℤ</span></code> to its <code class="docutils literal notranslate"><span class="pre">Module₁</span> <span class="pre">ℤ</span></code> going through either <code class="docutils literal notranslate"><span class="pre">AddCommGroup₃</span> <span class="pre">ℤ</span></code> or <code class="docutils literal notranslate"><span class="pre">Ring₃</span> <span class="pre">ℤ</span></code>.</p> <p>It is important to understand that not all diamonds are bad. In fact there are diamonds everywhere in mathlib, and also in this chapter. Already at the very beginning we saw one can go from <code class="docutils literal notranslate"><span class="pre">Monoid₁</span> <span class="pre">α</span></code> to <code class="docutils literal notranslate"><span class="pre">Dia₁</span> <span class="pre">α</span></code> through either <code class="docutils literal notranslate"><span class="pre">Semigroup₁</span> <span class="pre">α</span></code> or <code class="docutils literal notranslate"><span class="pre">DiaOneClass₁</span> <span class="pre">α</span></code> and thanks to the work done by the <code class="docutils literal notranslate"><span class="pre">class</span></code> command, the resulting two <code class="docutils literal notranslate"><span class="pre">Dia₁</span> <span class="pre">α</span></code> instances are definitionnaly equal. In particular a diamond having a <code class="docutils literal notranslate"><span class="pre">Prop</span></code>-valued class at the bottom cannot be bad since any too proofs of the same statement are definitionnaly equal.</p> <p>But the diamond we created with modules is definitely bad. The offending piece is the <code class="docutils literal notranslate"><span class="pre">smul</span></code> field which is data, not a proof, and we have two constructions that are not definitionnaly equal. The robust way of fixing this issue is to make sure that going from a rich structure to a poor structure is always done by forgetting data, not by defining data. This well-known pattern as been named “forgetful inheritance” and extensively discussed in <a class="reference external" href="https://inria.hal.science/hal-02463336">https://inria.hal.science/hal-02463336</a>.</p> <p>In our concrete case, we can modify the definition of <code class="docutils literal notranslate"><span class="pre">AddMonoid₃</span></code> to include a <code class="docutils literal notranslate"><span class="pre">nsmul</span></code> data field and some <code class="docutils literal notranslate"><span class="pre">Prop</span></code>-valued fields ensuring this operation is provably the one we constructed above. Those fields are given default values using <code class="docutils literal notranslate"><span class="pre">:=</span></code> after their type in the definition below. Thanks to these default values, most instances would be constructed exactly as with our previous definitions. But in the special case of <code class="docutils literal notranslate"><span class="pre">ℤ</span></code> we will be able to provide specific values.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">AddMonoid₄</span> <span class="o">(</span><span class="n">M</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="kd">extends</span> <span class="n">AddSemigroup₃</span> <span class="n">M</span><span class="o">,</span> <span class="n">AddZeroClass</span> <span class="n">M</span> <span class="n">where</span> <span class="sd">/-- Multiplication by a natural number. -/</span> <span class="n">nsmul</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">M</span> <span class="bp">→</span> <span class="n">M</span> <span class="o">:=</span> <span class="n">nsmul₁</span> <span class="sd">/-- Multiplication by `(0 : ℕ)` gives `0`. -/</span> <span class="n">nsmul_zero</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span><span class="o">,</span> <span class="n">nsmul</span> <span class="mi">0</span> <span class="n">x</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intros</span><span class="bp">;</span> <span class="n">rfl</span> <span class="sd">/-- Multiplication by `(n + 1 : ℕ)` behaves as expected. -/</span> <span class="n">nsmul_succ</span> <span class="o">:</span> <span class="bp">∀</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">x</span><span class="o">),</span> <span class="n">nsmul</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">nsmul</span> <span class="n">n</span> <span class="n">x</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intros</span><span class="bp">;</span> <span class="n">rfl</span> <span class="kd">instance</span> <span class="n">mySMul</span> <span class="o">{</span><span class="n">M</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">}</span> <span class="o">[</span><span class="n">AddMonoid₄</span> <span class="n">M</span><span class="o">]</span> <span class="o">:</span> <span class="n">SMul</span> <span class="n">ℕ</span> <span class="n">M</span> <span class="o">:=</span> <span class="o">⟨</span><span class="n">AddMonoid₄.nsmul</span><span class="o">⟩</span> </pre></div> </div> <p>Let us check we can still construct a product monoid instance without providing the <code class="docutils literal notranslate"><span class="pre">nsmul</span></code> related fields.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="o">(</span><span class="n">M</span> <span class="n">N</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">AddMonoid₄</span> <span class="n">M</span><span class="o">]</span> <span class="o">[</span><span class="n">AddMonoid₄</span> <span class="n">N</span><span class="o">]</span> <span class="o">:</span> <span class="n">AddMonoid₄</span> <span class="o">(</span><span class="n">M</span> <span class="bp">×</span> <span class="n">N</span><span class="o">)</span> <span class="n">where</span> <span class="n">add</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">p</span> <span class="n">q</span> <span class="bp">↦</span> <span class="o">(</span><span class="n">p.1</span> <span class="bp">+</span> <span class="n">q.1</span><span class="o">,</span> <span class="n">p.2</span> <span class="bp">+</span> <span class="n">q.2</span><span class="o">)</span> <span class="n">add_assoc₃</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="bp">↦</span> <span class="kd">by</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">apply</span> <span class="n">add_assoc₃</span> <span class="n">zero</span> <span class="o">:=</span> <span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">)</span> <span class="n">zero_add</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">a</span> <span class="bp">↦</span> <span class="kd">by</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">apply</span> <span class="n">zero_add</span> <span class="n">add_zero</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">a</span> <span class="bp">↦</span> <span class="kd">by</span> <span class="n">ext</span> <span class="bp"><;></span> <span class="n">apply</span> <span class="n">add_zero</span> </pre></div> </div> <p>And now let us handle the special case of <code class="docutils literal notranslate"><span class="pre">ℤ</span></code> where we want to build <code class="docutils literal notranslate"><span class="pre">nsmul</span></code> using the coercion of <code class="docutils literal notranslate"><span class="pre">ℕ</span></code> to <code class="docutils literal notranslate"><span class="pre">ℤ</span></code> and the multiplication on <code class="docutils literal notranslate"><span class="pre">ℤ</span></code>. Note in particular how the proof fields contain more work than in the default value above.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="o">:</span> <span class="n">AddMonoid₄</span> <span class="n">ℤ</span> <span class="n">where</span> <span class="n">add</span> <span class="o">:=</span> <span class="o">(</span><span class="bp">·</span> <span class="bp">+</span> <span class="bp">·</span><span class="o">)</span> <span class="n">add_assoc₃</span> <span class="o">:=</span> <span class="n">Int.add_assoc</span> <span class="n">zero</span> <span class="o">:=</span> <span class="mi">0</span> <span class="n">zero_add</span> <span class="o">:=</span> <span class="n">Int.zero_add</span> <span class="n">add_zero</span> <span class="o">:=</span> <span class="n">Int.add_zero</span> <span class="n">nsmul</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">n</span> <span class="n">m</span> <span class="bp">↦</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℤ</span><span class="o">)</span> <span class="bp">*</span> <span class="n">m</span> <span class="n">nsmul_zero</span> <span class="o">:=</span> <span class="n">Int.zero_mul</span> <span class="n">nsmul_succ</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">n</span> <span class="n">m</span> <span class="bp">↦</span> <span class="k">show</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span> <span class="o">:</span> <span class="n">ℤ</span><span class="o">)</span> <span class="bp">*</span> <span class="n">m</span> <span class="bp">=</span> <span class="n">m</span> <span class="bp">+</span> <span class="n">n</span> <span class="bp">*</span> <span class="n">m</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">Int.add_mul</span><span class="o">,</span> <span class="n">Int.add_comm</span><span class="o">,</span> <span class="n">Int.one_mul</span><span class="o">]</span> </pre></div> </div> <p>Let us check we solved our issue. Because Lean already has a definition of scalar multiplication of a natural number and an integer, and we want to make sure our instance is used, we won’t use the <code class="docutils literal notranslate"><span class="pre">•</span></code> notation but call <code class="docutils literal notranslate"><span class="pre">SMul.mul</span></code> and explicitly provide our instance defined above.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">m</span> <span class="o">:</span> <span class="n">ℤ</span><span class="o">)</span> <span class="o">:</span> <span class="n">SMul.smul</span> <span class="o">(</span><span class="n">self</span> <span class="o">:=</span> <span class="n">mySMul</span><span class="o">)</span> <span class="n">n</span> <span class="n">m</span> <span class="bp">=</span> <span class="n">n</span> <span class="bp">*</span> <span class="n">m</span> <span class="o">:=</span> <span class="n">rfl</span> </pre></div> </div> <p>This story then continues with incorporating a <code class="docutils literal notranslate"><span class="pre">zsmul</span></code> field into the definition of groups and similar tricks. You are now ready to read the definition of monoids, groups, rings and modules in mathlib. There are more complicated than what we have seen here, because they are part of a huge hierarchy, but all principles have been explained above.</p> <p>As an exercise, you can come back to the order relation hierarchy you built above and try to incorportate a type class <code class="docutils literal notranslate"><span class="pre">LT₁</span></code> carrying the Less-Than notation <code class="docutils literal notranslate"><span class="pre"><₁</span></code> and make sure that every preorder comes with a <code class="docutils literal notranslate"><span class="pre"><₁</span></code> which has a default value built from <code class="docutils literal notranslate"><span class="pre">≤₁</span></code> and a <code class="docutils literal notranslate"><span class="pre">Prop</span></code>-valued field asserting the natural relation between those two comparison operators. TEXT. -/</p> </section> <section id="morphisms"> <span id="section-hierarchies-morphisms"></span><h2><span class="section-number">7.2. </span>Morphisms<a class="headerlink" href="#morphisms" title="Permalink to this heading"></a></h2> <p>So far in this chapter, we discussed how to create a hierarchy of mathematical structures. But defining structures is not really completed until we have morphisms. There are two main approaches here. The most obvious one is to define a predicate on functions.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">isMonoidHom₁</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">G</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">H</span><span class="o">]</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">G</span> <span class="bp">→</span> <span class="n">H</span><span class="o">)</span> <span class="o">:</span> <span class="kt">Prop</span> <span class="o">:=</span> <span class="n">f</span> <span class="mi">1</span> <span class="bp">=</span> <span class="mi">1</span> <span class="bp">∧</span> <span class="bp">∀</span> <span class="n">g</span> <span class="n">g'</span><span class="o">,</span> <span class="n">f</span> <span class="o">(</span><span class="n">g</span> <span class="bp">*</span> <span class="n">g'</span><span class="o">)</span> <span class="bp">=</span> <span class="n">f</span> <span class="n">g</span> <span class="bp">*</span> <span class="n">f</span> <span class="n">g'</span> </pre></div> </div> <p>In this definition, it is a bit unpleasant to use a conjunction. In particular users will need to remember the ordering we chose when they want to access the two conditions. So we could use a structure instead.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">structure</span> <span class="n">isMonoidHom₂</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">G</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">H</span><span class="o">]</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">G</span> <span class="bp">→</span> <span class="n">H</span><span class="o">)</span> <span class="o">:</span> <span class="kt">Prop</span> <span class="n">where</span> <span class="n">map_one</span> <span class="o">:</span> <span class="n">f</span> <span class="mi">1</span> <span class="bp">=</span> <span class="mi">1</span> <span class="n">map_mul</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">g</span> <span class="n">g'</span><span class="o">,</span> <span class="n">f</span> <span class="o">(</span><span class="n">g</span> <span class="bp">*</span> <span class="n">g'</span><span class="o">)</span> <span class="bp">=</span> <span class="n">f</span> <span class="n">g</span> <span class="bp">*</span> <span class="n">f</span> <span class="n">g'</span> </pre></div> </div> <p>Once we are here, it is even tempting to make it a class and use the type class instance resolution procedure to automatically infer <code class="docutils literal notranslate"><span class="pre">isMonoidHom₂</span></code> for complicated functions out of instances for simpler functions. For instance a composition of monoid morphisms is a monoid morphism and this seems like a useful instance. However such an instance would be very tricky for the resolution procedure since it would need to hunt down <code class="docutils literal notranslate"><span class="pre">g</span> <span class="pre">∘</span> <span class="pre">f</span></code> everywhere. Seeing it failing in <code class="docutils literal notranslate"><span class="pre">g</span> <span class="pre">(f</span> <span class="pre">x)</span></code> would be very frustrating. More generally one must always keep in mind that recognizing which function is applied in a given expression is a very difficult problem, called the “higher-order unification problem”. So Mathlib does not use this class approach.</p> <p>A more fundamental question is whether we use predicates as above (using either a <code class="docutils literal notranslate"><span class="pre">def</span></code> or a <code class="docutils literal notranslate"><span class="pre">structure</span></code>) or use structures bundling a function and predicates. This is partly a psychological issue. It is extremely rare to consider a function between monoids that is not a morphism. It really feels like “monoid morphism” is not an adjective you can assign to a bare function, it is a noun. On the other hand one can argue that a continuous function between topological spaces is really a function that happens to be continuous. This is one reason why Mathlib has a <code class="docutils literal notranslate"><span class="pre">Continuous</span></code> predicate. For instance you can write:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="o">(</span><span class="n">id</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:=</span> <span class="n">continuous_id</span> </pre></div> </div> <p>We still have bundles continuous functions, which are convenient for instance to put a topology on a space of continuous functions, but they are not the primary tool to work with continuity.</p> <p>By constrast, morphisms between monoids (or other algebraic structures) are bundled as in:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">@[ext]</span> <span class="kd">structure</span> <span class="n">MonoidHom₁</span> <span class="o">(</span><span class="n">G</span> <span class="n">H</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">G</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">H</span><span class="o">]</span> <span class="n">where</span> <span class="n">toFun</span> <span class="o">:</span> <span class="n">G</span> <span class="bp">→</span> <span class="n">H</span> <span class="n">map_one</span> <span class="o">:</span> <span class="n">toFun</span> <span class="mi">1</span> <span class="bp">=</span> <span class="mi">1</span> <span class="n">map_mul</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">g</span> <span class="n">g'</span><span class="o">,</span> <span class="n">toFun</span> <span class="o">(</span><span class="n">g</span> <span class="bp">*</span> <span class="n">g'</span><span class="o">)</span> <span class="bp">=</span> <span class="n">toFun</span> <span class="n">g</span> <span class="bp">*</span> <span class="n">toFun</span> <span class="n">g'</span> </pre></div> </div> <p>Of course we don’t want to type <code class="docutils literal notranslate"><span class="pre">toFun</span></code> everywhere so we register a coercion using the <code class="docutils literal notranslate"><span class="pre">CoeFun</span></code> type class. Its first argument is the type we want to coerce to a function. The second argument describes the target function type. In our case it is always <code class="docutils literal notranslate"><span class="pre">G</span> <span class="pre">→</span> <span class="pre">H</span></code> for every <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">MonoidHom₁</span> <span class="pre">G</span> <span class="pre">H</span></code>. We also tag <code class="docutils literal notranslate"><span class="pre">MonoidHom₁.toFun</span></code> with the <code class="docutils literal notranslate"><span class="pre">coe</span></code> attribute to make sure it is displayed almost invisibly in the tactic state, simply by a <code class="docutils literal notranslate"><span class="pre">↑</span></code> prefix.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">G</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">H</span><span class="o">]</span> <span class="o">:</span> <span class="n">CoeFun</span> <span class="o">(</span><span class="n">MonoidHom₁</span> <span class="n">G</span> <span class="n">H</span><span class="o">)</span> <span class="o">(</span><span class="k">fun</span> <span class="n">_</span> <span class="bp">↦</span> <span class="n">G</span> <span class="bp">→</span> <span class="n">H</span><span class="o">)</span> <span class="n">where</span> <span class="n">coe</span> <span class="o">:=</span> <span class="n">MonoidHom₁.toFun</span> <span class="kn">attribute</span> <span class="o">[</span><span class="n">coe</span><span class="o">]</span> <span class="n">MonoidHom₁.toFun</span> </pre></div> </div> <p>Let us check we can indeed apply a bundled monoid morphism to an element.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">G</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">H</span><span class="o">]</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">MonoidHom₁</span> <span class="n">G</span> <span class="n">H</span><span class="o">)</span> <span class="o">:</span> <span class="n">f</span> <span class="mi">1</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">:=</span> <span class="n">f.map_one</span> </pre></div> </div> <p>We can do the same with other kind of morphisms until we reach ring morphisms.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">@[ext]</span> <span class="kd">structure</span> <span class="n">AddMonoidHom₁</span> <span class="o">(</span><span class="n">G</span> <span class="n">H</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">AddMonoid</span> <span class="n">G</span><span class="o">]</span> <span class="o">[</span><span class="n">AddMonoid</span> <span class="n">H</span><span class="o">]</span> <span class="n">where</span> <span class="n">toFun</span> <span class="o">:</span> <span class="n">G</span> <span class="bp">→</span> <span class="n">H</span> <span class="n">map_zero</span> <span class="o">:</span> <span class="n">toFun</span> <span class="mi">0</span> <span class="bp">=</span> <span class="mi">0</span> <span class="n">map_add</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">g</span> <span class="n">g'</span><span class="o">,</span> <span class="n">toFun</span> <span class="o">(</span><span class="n">g</span> <span class="bp">+</span> <span class="n">g'</span><span class="o">)</span> <span class="bp">=</span> <span class="n">toFun</span> <span class="n">g</span> <span class="bp">+</span> <span class="n">toFun</span> <span class="n">g'</span> <span class="kd">instance</span> <span class="o">[</span><span class="n">AddMonoid</span> <span class="n">G</span><span class="o">]</span> <span class="o">[</span><span class="n">AddMonoid</span> <span class="n">H</span><span class="o">]</span> <span class="o">:</span> <span class="n">CoeFun</span> <span class="o">(</span><span class="n">AddMonoidHom₁</span> <span class="n">G</span> <span class="n">H</span><span class="o">)</span> <span class="o">(</span><span class="k">fun</span> <span class="n">_</span> <span class="bp">↦</span> <span class="n">G</span> <span class="bp">→</span> <span class="n">H</span><span class="o">)</span> <span class="n">where</span> <span class="n">coe</span> <span class="o">:=</span> <span class="n">AddMonoidHom₁.toFun</span> <span class="kn">attribute</span> <span class="o">[</span><span class="n">coe</span><span class="o">]</span> <span class="n">AddMonoidHom₁.toFun</span> <span class="kd">@[ext]</span> <span class="kd">structure</span> <span class="n">RingHom₁</span> <span class="o">(</span><span class="n">R</span> <span class="n">S</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">Ring</span> <span class="n">R</span><span class="o">]</span> <span class="o">[</span><span class="n">Ring</span> <span class="n">S</span><span class="o">]</span> <span class="kd">extends</span> <span class="n">MonoidHom₁</span> <span class="n">R</span> <span class="n">S</span><span class="o">,</span> <span class="n">AddMonoidHom₁</span> <span class="n">R</span> <span class="n">S</span> </pre></div> </div> <p>There are a couple of issues about this approach. A minor one is we don’t quite know where to put the <code class="docutils literal notranslate"><span class="pre">coe</span></code> attribute since the <code class="docutils literal notranslate"><span class="pre">RingHom₁.toFun</span></code> does not exist, the relevant function is <code class="docutils literal notranslate"><span class="pre">MonoidHom₁.toFun</span> <span class="pre">∘</span> <span class="pre">RingHom₁.toMonoidHom₁</span></code> which is not a declaration that can be tagged with an attribute (but we could still define a <code class="docutils literal notranslate"><span class="pre">CoeFun</span>  <span class="pre">(RingHom₁</span> <span class="pre">R</span> <span class="pre">S)</span> <span class="pre">(fun</span> <span class="pre">_</span> <span class="pre">↦</span> <span class="pre">R</span> <span class="pre">→</span> <span class="pre">S)</span></code> instance). A much more important one is that lemmas about monoid morphisms won’t directly apply to ring morphisms. This leaves the alternative of either juggling with <code class="docutils literal notranslate"><span class="pre">RingHom₁.toMonoidHom₁</span></code> each time we want to apply a monoid morphism lemma or restate every such lemmas for ring morphisms. Neither option is appealing so Mathlib uses a new hierarchy trick here. The idea is to define a type class for objects that are at least monoid morphisms, instantiate that class with both monoid morphisms and ring morphisms and use it to state every lemma. In the definition below, <code class="docutils literal notranslate"><span class="pre">F</span></code> could be <code class="docutils literal notranslate"><span class="pre">MonoidHom₁</span> <span class="pre">M</span> <span class="pre">N</span></code>, or <code class="docutils literal notranslate"><span class="pre">RingHom₁</span> <span class="pre">M</span> <span class="pre">N</span></code> if <code class="docutils literal notranslate"><span class="pre">M</span></code> and <code class="docutils literal notranslate"><span class="pre">N</span></code> have a ring structure.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">MonoidHomClass₁</span> <span class="o">(</span><span class="n">F</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">(</span><span class="n">M</span> <span class="n">N</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">N</span><span class="o">]</span> <span class="n">where</span> <span class="n">toFun</span> <span class="o">:</span> <span class="n">F</span> <span class="bp">→</span> <span class="n">M</span> <span class="bp">→</span> <span class="n">N</span> <span class="n">map_one</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">f</span> <span class="o">:</span> <span class="n">F</span><span class="o">,</span> <span class="n">toFun</span> <span class="n">f</span> <span class="mi">1</span> <span class="bp">=</span> <span class="mi">1</span> <span class="n">map_mul</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">f</span> <span class="n">g</span> <span class="n">g'</span><span class="o">,</span> <span class="n">toFun</span> <span class="n">f</span> <span class="o">(</span><span class="n">g</span> <span class="bp">*</span> <span class="n">g'</span><span class="o">)</span> <span class="bp">=</span> <span class="n">toFun</span> <span class="n">f</span> <span class="n">g</span> <span class="bp">*</span> <span class="n">toFun</span> <span class="n">f</span> <span class="n">g'</span> </pre></div> </div> <p>However there is a problem with the above implementation. We haven’t registered a coercion to function instance yet. Let us try to do it now.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">badInst</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">N</span><span class="o">]</span> <span class="o">[</span><span class="n">MonoidHomClass₁</span> <span class="n">F</span> <span class="n">M</span> <span class="n">N</span><span class="o">]</span> <span class="o">:</span> <span class="n">CoeFun</span> <span class="n">F</span> <span class="o">(</span><span class="k">fun</span> <span class="n">_</span> <span class="bp">↦</span> <span class="n">M</span> <span class="bp">→</span> <span class="n">N</span><span class="o">)</span> <span class="n">where</span> <span class="n">coe</span> <span class="o">:=</span> <span class="n">MonoidHomClass₁.toFun</span> </pre></div> </div> <p>Making the an instance would be bad. When faced with something like <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span></code> where the type of <code class="docutils literal notranslate"><span class="pre">f</span></code> is not a function type, Lean will try to find a <code class="docutils literal notranslate"><span class="pre">CoeFun</span></code> instance to coerce <code class="docutils literal notranslate"><span class="pre">f</span></code> into a function. The above function has type: <code class="docutils literal notranslate"><span class="pre">{M</span> <span class="pre">N</span> <span class="pre">F</span> <span class="pre">:</span> <span class="pre">Type}</span> <span class="pre">→</span> <span class="pre">[Monoid</span> <span class="pre">M]</span> <span class="pre">→</span> <span class="pre">[Monoid</span> <span class="pre">N]</span> <span class="pre">→</span> <span class="pre">[MonoidHomClass₁</span> <span class="pre">F</span> <span class="pre">M</span> <span class="pre">N]</span> <span class="pre">→</span> <span class="pre">CoeFun</span> <span class="pre">F</span> <span class="pre">(fun</span> <span class="pre">x</span> <span class="pre">↦</span> <span class="pre">M</span> <span class="pre">→</span> <span class="pre">N)</span></code> so, when it trying to apply it, it wouldn’t be a priori clear to Lean in which order the unknown types <code class="docutils literal notranslate"><span class="pre">M</span></code>, <code class="docutils literal notranslate"><span class="pre">N</span></code> and <code class="docutils literal notranslate"><span class="pre">F</span></code> should be inferred. This is a kind of bad instance that is slightly different from the one we saw already, but it boils down to the same issue: without knowing <code class="docutils literal notranslate"><span class="pre">M</span></code>, Lean would have to search for a monoid instance on an unknown type, hence hopelessly try <em>every</em> monoid instance in the database. If you are curious to see the effect of such an instance you can type <code class="docutils literal notranslate"><span class="pre">set_option</span> <span class="pre">synthInstance.checkSynthOrder</span> <span class="pre">false</span> <span class="pre">in</span></code> on top of the above declaration, replace <code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">badInst</span></code> with <code class="docutils literal notranslate"><span class="pre">instance</span></code>, and look for random failures in this file.</p> <p>Here the solution is easy, we need to tell Lean to first search what is <code class="docutils literal notranslate"><span class="pre">F</span></code> and then deduce <code class="docutils literal notranslate"><span class="pre">M</span></code> and <code class="docutils literal notranslate"><span class="pre">N</span></code>. This is done using the <code class="docutils literal notranslate"><span class="pre">outParam</span></code> function. This function is defined as the identity function, but is still recognized by the type class machinery and triggers the desired behavior. Hence we can retry defining our class, paying attention to the <code class="docutils literal notranslate"><span class="pre">outParam</span></code> function:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">MonoidHomClass₂</span> <span class="o">(</span><span class="n">F</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">(</span><span class="n">M</span> <span class="n">N</span> <span class="o">:</span> <span class="n">outParam</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">N</span><span class="o">]</span> <span class="n">where</span> <span class="n">toFun</span> <span class="o">:</span> <span class="n">F</span> <span class="bp">→</span> <span class="n">M</span> <span class="bp">→</span> <span class="n">N</span> <span class="n">map_one</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">f</span> <span class="o">:</span> <span class="n">F</span><span class="o">,</span> <span class="n">toFun</span> <span class="n">f</span> <span class="mi">1</span> <span class="bp">=</span> <span class="mi">1</span> <span class="n">map_mul</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">f</span> <span class="n">g</span> <span class="n">g'</span><span class="o">,</span> <span class="n">toFun</span> <span class="n">f</span> <span class="o">(</span><span class="n">g</span> <span class="bp">*</span> <span class="n">g'</span><span class="o">)</span> <span class="bp">=</span> <span class="n">toFun</span> <span class="n">f</span> <span class="n">g</span> <span class="bp">*</span> <span class="n">toFun</span> <span class="n">f</span> <span class="n">g'</span> <span class="kd">instance</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">N</span><span class="o">]</span> <span class="o">[</span><span class="n">MonoidHomClass₂</span> <span class="n">F</span> <span class="n">M</span> <span class="n">N</span><span class="o">]</span> <span class="o">:</span> <span class="n">CoeFun</span> <span class="n">F</span> <span class="o">(</span><span class="k">fun</span> <span class="n">_</span> <span class="bp">↦</span> <span class="n">M</span> <span class="bp">→</span> <span class="n">N</span><span class="o">)</span> <span class="n">where</span> <span class="n">coe</span> <span class="o">:=</span> <span class="n">MonoidHomClass₂.toFun</span> <span class="kn">attribute</span> <span class="o">[</span><span class="n">coe</span><span class="o">]</span> <span class="n">MonoidHomClass₂.toFun</span> </pre></div> </div> <p>Now we can proceed with our plan to instantiate this class.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="o">(</span><span class="n">M</span> <span class="n">N</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">N</span><span class="o">]</span> <span class="o">:</span> <span class="n">MonoidHomClass₂</span> <span class="o">(</span><span class="n">MonoidHom₁</span> <span class="n">M</span> <span class="n">N</span><span class="o">)</span> <span class="n">M</span> <span class="n">N</span> <span class="n">where</span> <span class="n">toFun</span> <span class="o">:=</span> <span class="n">MonoidHom₁.toFun</span> <span class="n">map_one</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">f</span> <span class="bp">↦</span> <span class="n">f.map_one</span> <span class="n">map_mul</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">f</span> <span class="bp">↦</span> <span class="n">f.map_mul</span> <span class="kd">instance</span> <span class="o">(</span><span class="n">R</span> <span class="n">S</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">Ring</span> <span class="n">R</span><span class="o">]</span> <span class="o">[</span><span class="n">Ring</span> <span class="n">S</span><span class="o">]</span> <span class="o">:</span> <span class="n">MonoidHomClass₂</span> <span class="o">(</span><span class="n">RingHom₁</span> <span class="n">R</span> <span class="n">S</span><span class="o">)</span> <span class="n">R</span> <span class="n">S</span> <span class="n">where</span> <span class="n">toFun</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">f</span> <span class="bp">↦</span> <span class="n">f.toMonoidHom₁.toFun</span> <span class="n">map_one</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">f</span> <span class="bp">↦</span> <span class="n">f.toMonoidHom₁.map_one</span> <span class="n">map_mul</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">f</span> <span class="bp">↦</span> <span class="n">f.toMonoidHom₁.map_mul</span> </pre></div> </div> <p>As promised every lemma we prove about <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">F</span></code> assuming an instance of <code class="docutils literal notranslate"><span class="pre">MonoidHomClass₁</span> <span class="pre">F</span></code> will apply both to monoid morphims and ring morphisms. Let us see an example lemma and check it applies to both situations.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">lemma</span> <span class="n">map_inv_of_inv</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">N</span><span class="o">]</span> <span class="o">[</span><span class="n">MonoidHomClass₂</span> <span class="n">F</span> <span class="n">M</span> <span class="n">N</span><span class="o">]</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">F</span><span class="o">)</span> <span class="o">{</span><span class="n">m</span> <span class="n">m'</span> <span class="o">:</span> <span class="n">M</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">m</span><span class="bp">*</span><span class="n">m'</span> <span class="bp">=</span> <span class="mi">1</span><span class="o">)</span> <span class="o">:</span> <span class="n">f</span> <span class="n">m</span> <span class="bp">*</span> <span class="n">f</span> <span class="n">m'</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="bp">←</span> <span class="n">MonoidHomClass₂.map_mul</span><span class="o">,</span> <span class="n">h</span><span class="o">,</span> <span class="n">MonoidHomClass₂.map_one</span><span class="o">]</span> <span class="kd">example</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">N</span><span class="o">]</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">MonoidHom₁</span> <span class="n">M</span> <span class="n">N</span><span class="o">)</span> <span class="o">{</span><span class="n">m</span> <span class="n">m'</span> <span class="o">:</span> <span class="n">M</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">m</span><span class="bp">*</span><span class="n">m'</span> <span class="bp">=</span> <span class="mi">1</span><span class="o">)</span> <span class="o">:</span> <span class="n">f</span> <span class="n">m</span> <span class="bp">*</span> <span class="n">f</span> <span class="n">m'</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">:=</span> <span class="n">map_inv_of_inv</span> <span class="n">f</span> <span class="n">h</span> <span class="kd">example</span> <span class="o">[</span><span class="n">Ring</span> <span class="n">R</span><span class="o">]</span> <span class="o">[</span><span class="n">Ring</span> <span class="n">S</span><span class="o">]</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">RingHom₁</span> <span class="n">R</span> <span class="n">S</span><span class="o">)</span> <span class="o">{</span><span class="n">r</span> <span class="n">r'</span> <span class="o">:</span> <span class="n">R</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">r</span><span class="bp">*</span><span class="n">r'</span> <span class="bp">=</span> <span class="mi">1</span><span class="o">)</span> <span class="o">:</span> <span class="n">f</span> <span class="n">r</span> <span class="bp">*</span> <span class="n">f</span> <span class="n">r'</span> <span class="bp">=</span> <span class="mi">1</span> <span class="o">:=</span> <span class="n">map_inv_of_inv</span> <span class="n">f</span> <span class="n">h</span> </pre></div> </div> <p>At first sight, it may look like we got back to our old bad idea of making <code class="docutils literal notranslate"><span class="pre">MonoidHom₁</span></code> a class. But we haven’t. Everything is shifted one level of abstraction up. The type class resolution procedure won’t be looking for functions, it will be looking for either <code class="docutils literal notranslate"><span class="pre">MonoidHom₁</span></code> or <code class="docutils literal notranslate"><span class="pre">RingHom₁</span></code>.</p> <p>One remaining issue with our approach is the presence of repeatitive code around the <code class="docutils literal notranslate"><span class="pre">toFun</span></code> field and the corresponding <code class="docutils literal notranslate"><span class="pre">CoeFun</span></code> instance and <code class="docutils literal notranslate"><span class="pre">coe</span></code> attribute. It would also be better to record that this pattern is used only for function with extra properties, meaning that the coercion to functions should be injective. So Mathlib adds one more layer of abstraction with the base class <code class="docutils literal notranslate"><span class="pre">FunLike</span></code>. Let us redefine our <code class="docutils literal notranslate"><span class="pre">MonoidHomClass</span></code> on top of this base layer.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">MonoidHomClass₃</span> <span class="o">(</span><span class="n">F</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">(</span><span class="n">M</span> <span class="n">N</span> <span class="o">:</span> <span class="n">outParam</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">N</span><span class="o">]</span> <span class="kd">extends</span> <span class="n">FunLike</span> <span class="n">F</span> <span class="n">M</span> <span class="o">(</span><span class="k">fun</span> <span class="n">_</span> <span class="bp">↦</span> <span class="n">N</span><span class="o">)</span> <span class="n">where</span> <span class="n">map_one</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">f</span> <span class="o">:</span> <span class="n">F</span><span class="o">,</span> <span class="n">f</span> <span class="mi">1</span> <span class="bp">=</span> <span class="mi">1</span> <span class="n">map_mul</span> <span class="o">:</span> <span class="bp">∀</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">F</span><span class="o">)</span> <span class="n">g</span> <span class="n">g'</span><span class="o">,</span> <span class="n">f</span> <span class="o">(</span><span class="n">g</span> <span class="bp">*</span> <span class="n">g'</span><span class="o">)</span> <span class="bp">=</span> <span class="n">f</span> <span class="n">g</span> <span class="bp">*</span> <span class="n">f</span> <span class="n">g'</span> <span class="kd">instance</span> <span class="o">(</span><span class="n">M</span> <span class="n">N</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">N</span><span class="o">]</span> <span class="o">:</span> <span class="n">MonoidHomClass₃</span> <span class="o">(</span><span class="n">MonoidHom₁</span> <span class="n">M</span> <span class="n">N</span><span class="o">)</span> <span class="n">M</span> <span class="n">N</span> <span class="n">where</span> <span class="n">coe</span> <span class="o">:=</span> <span class="n">MonoidHom₁.toFun</span> <span class="n">coe_injective'</span> <span class="o">:=</span> <span class="n">MonoidHom₁.ext</span> <span class="n">map_one</span> <span class="o">:=</span> <span class="n">MonoidHom₁.map_one</span> <span class="n">map_mul</span> <span class="o">:=</span> <span class="n">MonoidHom₁.map_mul</span> </pre></div> </div> <p>Of course the hierarchy of morphisms does not stop here. We could go on and define a class <code class="docutils literal notranslate"><span class="pre">RingHomClass₃</span></code> extending <code class="docutils literal notranslate"><span class="pre">MonoidHomClass₃</span></code> and instantiate it on <code class="docutils literal notranslate"><span class="pre">RingHom</span></code> and then later on <code class="docutils literal notranslate"><span class="pre">AlgebraHom</span></code> (algebras are rings with some extra structure). But we’ve covered the main formalization ideas used in Mathlib for morphisms and you should be ready to understand how morphisms are defined in Mathlib.</p> <p>As an exercise, you should try to define your class of bundled order-preserving function between ordered types, and then order preserving monoid morphisms. This is for training purposes only. Like continuous functions, order preserving functions are primarily unbundled in Mathlib where they are defined by the <code class="docutils literal notranslate"><span class="pre">Monotone</span></code> predicate. Of course you need to complete the class definitions below.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">@[ext]</span> <span class="kd">structure</span> <span class="n">OrderPresHom</span> <span class="o">(</span><span class="n">α</span> <span class="n">β</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">LE</span> <span class="n">α</span><span class="o">]</span> <span class="o">[</span><span class="n">LE</span> <span class="n">β</span><span class="o">]</span> <span class="n">where</span> <span class="n">toFun</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">β</span> <span class="n">le_of_le</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="n">a'</span><span class="o">,</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">a'</span> <span class="bp">→</span> <span class="n">toFun</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">toFun</span> <span class="n">a'</span> <span class="kd">@[ext]</span> <span class="kd">structure</span> <span class="n">OrderPresMonoidHom</span> <span class="o">(</span><span class="n">M</span> <span class="n">N</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">[</span><span class="n">LE</span> <span class="n">M</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">N</span><span class="o">]</span> <span class="o">[</span><span class="n">LE</span> <span class="n">N</span><span class="o">]</span> <span class="kd">extends</span> <span class="n">MonoidHom₁</span> <span class="n">M</span> <span class="n">N</span><span class="o">,</span> <span class="n">OrderPresHom</span> <span class="n">M</span> <span class="n">N</span> <span class="kd">class</span> <span class="n">OrderPresHomClass</span> <span class="o">(</span><span class="n">F</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">(</span><span class="n">α</span> <span class="n">β</span> <span class="o">:</span> <span class="n">outParam</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">LE</span> <span class="n">α</span><span class="o">]</span> <span class="o">[</span><span class="n">LE</span> <span class="n">β</span><span class="o">]</span> <span class="kd">instance</span> <span class="o">(</span><span class="n">α</span> <span class="n">β</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">LE</span> <span class="n">α</span><span class="o">]</span> <span class="o">[</span><span class="n">LE</span> <span class="n">β</span><span class="o">]</span> <span class="o">:</span> <span class="n">OrderPresHomClass</span> <span class="o">(</span><span class="n">OrderPresHom</span> <span class="n">α</span> <span class="n">β</span><span class="o">)</span> <span class="n">α</span> <span class="n">β</span> <span class="n">where</span> <span class="kd">instance</span> <span class="o">(</span><span class="n">α</span> <span class="n">β</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">LE</span> <span class="n">α</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">α</span><span class="o">]</span> <span class="o">[</span><span class="n">LE</span> <span class="n">β</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">β</span><span class="o">]</span> <span class="o">:</span> <span class="n">OrderPresHomClass</span> <span class="o">(</span><span class="n">OrderPresMonoidHom</span> <span class="n">α</span> <span class="n">β</span><span class="o">)</span> <span class="n">α</span> <span class="n">β</span> <span class="n">where</span> <span class="kd">instance</span> <span class="o">(</span><span class="n">α</span> <span class="n">β</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">LE</span> <span class="n">α</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">α</span><span class="o">]</span> <span class="o">[</span><span class="n">LE</span> <span class="n">β</span><span class="o">]</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">β</span><span class="o">]</span> <span class="o">:</span> <span class="n">MonoidHomClass₃</span> <span class="o">(</span><span class="n">OrderPresMonoidHom</span> <span class="n">α</span> <span class="n">β</span><span class="o">)</span> <span class="n">α</span> <span class="n">β</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> </section> <section id="sub-objects"> <span id="section-hierarchies-subobjects"></span><h2><span class="section-number">7.3. </span>Sub-objects<a class="headerlink" href="#sub-objects" title="Permalink to this heading"></a></h2> <p>After defining some algebraic structure and its morphisms, the next step is to consider sets that inherit this algebraic structure, for instance subgroups or subrings. This largely overlaps our previous topic. Indeed a set in <code class="docutils literal notranslate"><span class="pre">X</span></code> is implemented as a function from <code class="docutils literal notranslate"><span class="pre">X</span></code> to <code class="docutils literal notranslate"><span class="pre">Prop</span></code> so sub-objects are function satisfying a certain predicate. Hence we can reuse of lot of the ideas that led to the <code class="docutils literal notranslate"><span class="pre">FunLike</span></code> class and its descendants. We won’t reuse <code class="docutils literal notranslate"><span class="pre">FunLike</span></code> itself because this would break the abstraction barrier from <code class="docutils literal notranslate"><span class="pre">Set</span> <span class="pre">X</span></code> to <code class="docutils literal notranslate"><span class="pre">X</span> <span class="pre">→</span> <span class="pre">Prop</span></code>. Instead there is a <code class="docutils literal notranslate"><span class="pre">SetLike</span></code> class. Instead of wrapping an injection into a function type, that class wraps an injection into a <code class="docutils literal notranslate"><span class="pre">Set</span></code> type and defines the corresponding coercion and <code class="docutils literal notranslate"><span class="pre">Membership</span></code> instance.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">@[ext]</span> <span class="kd">structure</span> <span class="n">Submonoid₁</span> <span class="o">(</span><span class="n">M</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="n">where</span> <span class="sd">/-- The carrier of a submonoid. -/</span> <span class="n">carrier</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">M</span> <span class="sd">/-- The product of two elements of a submonoid belongs to the submonoid. -/</span> <span class="n">mul_mem</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span><span class="o">}</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">∈</span> <span class="n">carrier</span> <span class="bp">→</span> <span class="n">b</span> <span class="bp">∈</span> <span class="n">carrier</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">∈</span> <span class="n">carrier</span> <span class="sd">/-- The unit element belongs to the submonoid. -/</span> <span class="n">one_mem</span> <span class="o">:</span> <span class="mi">1</span> <span class="bp">∈</span> <span class="n">carrier</span> <span class="sd">/-- Submonoids in `M` can be seen as sets in `M`. -/</span> <span class="kd">instance</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">:</span> <span class="n">SetLike</span> <span class="o">(</span><span class="n">Submonoid₁</span> <span class="n">M</span><span class="o">)</span> <span class="n">M</span> <span class="n">where</span> <span class="n">coe</span> <span class="o">:=</span> <span class="n">Submonoid₁.carrier</span> <span class="n">coe_injective'</span> <span class="o">:=</span> <span class="n">Submonoid₁.ext</span> </pre></div> </div> <p>Equipped with the above <code class="docutils literal notranslate"><span class="pre">SetLike</span></code> instance, we can already state naturally that a submonoid <code class="docutils literal notranslate"><span class="pre">N</span></code> contains <code class="docutils literal notranslate"><span class="pre">1</span></code> without using <code class="docutils literal notranslate"><span class="pre">N.carrier</span></code>. We can also silently treat <code class="docutils literal notranslate"><span class="pre">N</span></code> as a set in <code class="docutils literal notranslate"><span class="pre">M</span></code> as take its direct image under a map.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">(</span><span class="n">N</span> <span class="o">:</span> <span class="n">Submonoid₁</span> <span class="n">M</span><span class="o">)</span> <span class="o">:</span> <span class="mi">1</span> <span class="bp">∈</span> <span class="n">N</span> <span class="o">:=</span> <span class="n">N.one_mem</span> <span class="kd">example</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">(</span><span class="n">N</span> <span class="o">:</span> <span class="n">Submonoid₁</span> <span class="n">M</span><span class="o">)</span> <span class="o">(</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">M</span> <span class="bp">→</span> <span class="n">α</span><span class="o">)</span> <span class="o">:=</span> <span class="n">f</span> <span class="bp">''</span> <span class="n">N</span> </pre></div> </div> <p>We also have a coercion to <code class="docutils literal notranslate"><span class="pre">Type</span></code> which uses <code class="docutils literal notranslate"><span class="pre">Subtype</span></code> so, given a submonoid <code class="docutils literal notranslate"><span class="pre">N</span></code> we can write a parameter <code class="docutils literal notranslate"><span class="pre">(x</span> <span class="pre">:</span> <span class="pre">N)</span></code> which can be coerced to an element of <code class="docutils literal notranslate"><span class="pre">M</span></code> belonging to <code class="docutils literal notranslate"><span class="pre">N</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">(</span><span class="n">N</span> <span class="o">:</span> <span class="n">Submonoid₁</span> <span class="n">M</span><span class="o">)</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">N</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">M</span><span class="o">)</span> <span class="bp">∈</span> <span class="n">N</span> <span class="o">:=</span> <span class="n">x.property</span> </pre></div> </div> <p>Using this coercion to <code class="docutils literal notranslate"><span class="pre">Type</span></code> we can also tackle the task of equipping a submonoid with a monoid structure. We will use the coercion from the type associated to <code class="docutils literal notranslate"><span class="pre">N</span></code> as above, and the lemma <code class="docutils literal notranslate"><span class="pre">SetCoe.ext</span></code> asserting this coercion is injective. Both are provided by the <code class="docutils literal notranslate"><span class="pre">SetLike</span></code> instance.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="n">SubMonoid₁Monoid</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">(</span><span class="n">N</span> <span class="o">:</span> <span class="n">Submonoid₁</span> <span class="n">M</span><span class="o">)</span> <span class="o">:</span> <span class="n">Monoid</span> <span class="n">N</span> <span class="n">where</span> <span class="n">mul</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">x</span> <span class="n">y</span> <span class="bp">↦</span> <span class="o">⟨</span><span class="n">x</span><span class="bp">*</span><span class="n">y</span><span class="o">,</span> <span class="n">N.mul_mem</span> <span class="n">x.property</span> <span class="n">y.property</span><span class="o">⟩</span> <span class="n">mul_assoc</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="bp">↦</span> <span class="n">SetCoe.ext</span> <span class="o">(</span><span class="n">mul_assoc</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">M</span><span class="o">)</span> <span class="n">y</span> <span class="n">z</span><span class="o">)</span> <span class="n">one</span> <span class="o">:=</span> <span class="o">⟨</span><span class="mi">1</span><span class="o">,</span> <span class="n">N.one_mem</span><span class="o">⟩</span> <span class="n">one_mul</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">↦</span> <span class="n">SetCoe.ext</span> <span class="o">(</span><span class="n">one_mul</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">M</span><span class="o">))</span> <span class="n">mul_one</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">↦</span> <span class="n">SetCoe.ext</span> <span class="o">(</span><span class="n">mul_one</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">M</span><span class="o">))</span> </pre></div> </div> <p>Note that, in the above instance, instead of using the coercion to <code class="docutils literal notranslate"><span class="pre">M</span></code> and calling the <code class="docutils literal notranslate"><span class="pre">property</span></code> field, we could have used destructuring binders as follows.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">(</span><span class="n">N</span> <span class="o">:</span> <span class="n">Submonoid₁</span> <span class="n">M</span><span class="o">)</span> <span class="o">:</span> <span class="n">Monoid</span> <span class="n">N</span> <span class="n">where</span> <span class="n">mul</span> <span class="o">:=</span> <span class="k">fun</span> <span class="o">⟨</span><span class="n">x</span><span class="o">,</span> <span class="n">hx</span><span class="o">⟩</span> <span class="o">⟨</span><span class="n">y</span><span class="o">,</span> <span class="n">hy</span><span class="o">⟩</span> <span class="bp">↦</span> <span class="o">⟨</span><span class="n">x</span><span class="bp">*</span><span class="n">y</span><span class="o">,</span> <span class="n">N.mul_mem</span> <span class="n">hx</span> <span class="n">hy</span><span class="o">⟩</span> <span class="n">mul_assoc</span> <span class="o">:=</span> <span class="k">fun</span> <span class="o">⟨</span><span class="n">x</span><span class="o">,</span> <span class="n">_</span><span class="o">⟩</span> <span class="o">⟨</span><span class="n">y</span><span class="o">,</span> <span class="n">_</span><span class="o">⟩</span> <span class="o">⟨</span><span class="n">z</span><span class="o">,</span> <span class="n">_</span><span class="o">⟩</span> <span class="bp">↦</span> <span class="n">SetCoe.ext</span> <span class="o">(</span><span class="n">mul_assoc</span> <span class="n">x</span> <span class="n">y</span> <span class="n">z</span><span class="o">)</span> <span class="n">one</span> <span class="o">:=</span> <span class="o">⟨</span><span class="mi">1</span><span class="o">,</span> <span class="n">N.one_mem</span><span class="o">⟩</span> <span class="n">one_mul</span> <span class="o">:=</span> <span class="k">fun</span> <span class="o">⟨</span><span class="n">x</span><span class="o">,</span> <span class="n">_</span><span class="o">⟩</span> <span class="bp">↦</span> <span class="n">SetCoe.ext</span> <span class="o">(</span><span class="n">one_mul</span> <span class="n">x</span><span class="o">)</span> <span class="n">mul_one</span> <span class="o">:=</span> <span class="k">fun</span> <span class="o">⟨</span><span class="n">x</span><span class="o">,</span> <span class="n">_</span><span class="o">⟩</span> <span class="bp">↦</span> <span class="n">SetCoe.ext</span> <span class="o">(</span><span class="n">mul_one</span> <span class="n">x</span><span class="o">)</span> </pre></div> </div> <p>In order to apply lemmas about submonoids to subgroups or subrings, we need a class, just like for morphisms. Note this class take a <code class="docutils literal notranslate"><span class="pre">SetLike</span></code> instance as a parameter so it does not need a carrier field and can use the membership notation in its fields.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">class</span> <span class="n">SubmonoidClass₁</span> <span class="o">(</span><span class="n">S</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">(</span><span class="n">M</span> <span class="o">:</span> <span class="kt">Type</span><span class="o">)</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">[</span><span class="n">SetLike</span> <span class="n">S</span> <span class="n">M</span><span class="o">]</span> <span class="o">:</span> <span class="kt">Prop</span> <span class="n">where</span> <span class="n">mul_mem</span> <span class="o">:</span> <span class="bp">∀</span> <span class="o">(</span><span class="n">s</span> <span class="o">:</span> <span class="n">S</span><span class="o">)</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">M</span><span class="o">},</span> <span class="n">a</span> <span class="bp">∈</span> <span class="n">s</span> <span class="bp">→</span> <span class="n">b</span> <span class="bp">∈</span> <span class="n">s</span> <span class="bp">→</span> <span class="n">a</span> <span class="bp">*</span> <span class="n">b</span> <span class="bp">∈</span> <span class="n">s</span> <span class="n">one_mem</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">s</span> <span class="o">:</span> <span class="n">S</span><span class="o">,</span> <span class="mi">1</span> <span class="bp">∈</span> <span class="n">s</span> <span class="kd">instance</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">:</span> <span class="n">SubmonoidClass₁</span> <span class="o">(</span><span class="n">Submonoid₁</span> <span class="n">M</span><span class="o">)</span> <span class="n">M</span> <span class="n">where</span> <span class="n">mul_mem</span> <span class="o">:=</span> <span class="n">Submonoid₁.mul_mem</span> <span class="n">one_mem</span> <span class="o">:=</span> <span class="n">Submonoid₁.one_mem</span> </pre></div> </div> <p>As an exercise you should define a <code class="docutils literal notranslate"><span class="pre">Subgroup₁</span></code> structure, endow it with a <code class="docutils literal notranslate"><span class="pre">SetLike</span></code> instance and a <code class="docutils literal notranslate"><span class="pre">SubmonoidClass₁</span></code> instance, put a <code class="docutils literal notranslate"><span class="pre">Group</span></code> instance on the subtype associated to a <code class="docutils literal notranslate"><span class="pre">Subgroup₁</span></code> and define a <code class="docutils literal notranslate"><span class="pre">SubgroupClass₁</span></code> class.</p> <p>Another very important thing to know about subobjects of a given algebraic object in Mathlib always form a complete lattice, and this structure is used a lot. For instance you may look for the lemma saying that an intersection of submonoids is a submonoid. But this won’t be a lemma, this will be an infimum construction. Let us do the case of two submonoids.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">instance</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">:</span> <span class="n">Inf</span> <span class="o">(</span><span class="n">Submonoid₁</span> <span class="n">M</span><span class="o">)</span> <span class="o">:=</span> <span class="o">⟨</span><span class="k">fun</span> <span class="n">S₁</span> <span class="n">S₂</span> <span class="bp">=></span> <span class="o">{</span> <span class="n">carrier</span> <span class="o">:=</span> <span class="n">S₁</span> <span class="bp">∩</span> <span class="n">S₂</span> <span class="n">one_mem</span> <span class="o">:=</span> <span class="o">⟨</span><span class="n">S₁.one_mem</span><span class="o">,</span> <span class="n">S₂.one_mem</span><span class="o">⟩</span> <span class="n">mul_mem</span> <span class="o">:=</span> <span class="k">fun</span> <span class="o">⟨</span><span class="n">hx</span><span class="o">,</span> <span class="n">hx'</span><span class="o">⟩</span> <span class="o">⟨</span><span class="n">hy</span><span class="o">,</span> <span class="n">hy'</span><span class="o">⟩</span> <span class="bp">↦</span> <span class="o">⟨</span><span class="n">S₁.mul_mem</span> <span class="n">hx</span> <span class="n">hy</span><span class="o">,</span> <span class="n">S₂.mul_mem</span> <span class="n">hx'</span> <span class="n">hy'</span><span class="o">⟩</span> <span class="o">}⟩</span> </pre></div> </div> <p>This allows to get the intersections of two submonoids as a submonoid.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">[</span><span class="n">Monoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">(</span><span class="n">N</span> <span class="n">P</span> <span class="o">:</span> <span class="n">Submonoid₁</span> <span class="n">M</span><span class="o">)</span> <span class="o">:</span> <span class="n">Submonoid₁</span> <span class="n">M</span> <span class="o">:=</span> <span class="n">N</span> <span class="bp">⊓</span> <span class="n">P</span> </pre></div> </div> <p>You may think it’s a shame that we had to use the inf symbol <code class="docutils literal notranslate"><span class="pre">⊓</span></code> in the above example instead of the intersection symbol <code class="docutils literal notranslate"><span class="pre">∩</span></code>. But think about the supremum. The union of two submonoids is not a submonoid. However submonoids still form a lattice (even a complete one). Actually <code class="docutils literal notranslate"><span class="pre">N</span> <span class="pre">⊔</span> <span class="pre">P</span></code> is the submonoid generated by the union of <code class="docutils literal notranslate"><span class="pre">N</span></code> and <code class="docutils literal notranslate"><span class="pre">P</span></code> and of course it would be very confusing to denote it by <code class="docutils literal notranslate"><span class="pre">N</span> <span class="pre">∪</span> <span class="pre">P</span></code>. So you can see the use of <code class="docutils literal notranslate"><span class="pre">N</span> <span class="pre">⊓</span> <span class="pre">P</span></code> as much more consistent. It is also a lot more consistent across various kind of algebraic structures. It may look a bit weird at first to see the sum of two vector subspace <code class="docutils literal notranslate"><span class="pre">E</span></code> and <code class="docutils literal notranslate"><span class="pre">F</span></code> denoted by <code class="docutils literal notranslate"><span class="pre">E</span> <span class="pre">⊔</span> <span class="pre">F</span></code> instead of <code class="docutils literal notranslate"><span class="pre">E</span> <span class="pre">+</span> <span class="pre">F</span></code>. But you will get used to it. And soon you will consider the <code class="docutils literal notranslate"><span class="pre">E</span> <span class="pre">+</span> <span class="pre">F</span></code> notation as a distraction emphasizing the anecdotal fact that elements of <code class="docutils literal notranslate"><span class="pre">E</span> <span class="pre">⊔</span> <span class="pre">F</span></code> can be written as a sum of an element of <code class="docutils literal notranslate"><span class="pre">E</span></code> and an element of <code class="docutils literal notranslate"><span class="pre">F</span></code> instead of emphasizing the fundamental fact that <code class="docutils literal notranslate"><span class="pre">E</span> <span class="pre">⊔</span> <span class="pre">F</span></code> is the smallest vector subspace containing both <code class="docutils literal notranslate"><span class="pre">E</span></code> and <code class="docutils literal notranslate"><span class="pre">F</span></code>.</p> <p>Our last topic for this chapter is that of quotients. Again we want to explain how convenient notation are built and code duplication is avoided in Mathlib. Here the main device is the <code class="docutils literal notranslate"><span class="pre">HasQuotient</span></code> class which allows notations like <code class="docutils literal notranslate"><span class="pre">M</span> <span class="pre">⧸</span> <span class="pre">N</span></code>. Beware the quotient symbol <code class="docutils literal notranslate"><span class="pre">⧸</span></code> is a special unicode character, not a regular ASCII division symbol.</p> <p>As an example, we will build the quotient of a commutative monoid by a submonoid, leave proofs to you.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">Submonoid.Setoid</span> <span class="o">[</span><span class="n">CommMonoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">(</span><span class="n">N</span> <span class="o">:</span> <span class="n">Submonoid</span> <span class="n">M</span><span class="o">)</span> <span class="o">:</span> <span class="n">Setoid</span> <span class="n">M</span> <span class="n">where</span> <span class="n">r</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">x</span> <span class="n">y</span> <span class="bp">↦</span> <span class="bp">∃</span> <span class="n">w</span> <span class="bp">∈</span> <span class="n">N</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">z</span> <span class="bp">∈</span> <span class="n">N</span><span class="o">,</span> <span class="n">x</span><span class="bp">*</span><span class="n">w</span> <span class="bp">=</span> <span class="n">y</span><span class="bp">*</span><span class="n">z</span> <span class="n">iseqv</span> <span class="o">:=</span> <span class="o">{</span> <span class="n">refl</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">↦</span> <span class="o">⟨</span><span class="mi">1</span><span class="o">,</span> <span class="n">N.one_mem</span><span class="o">,</span> <span class="mi">1</span><span class="o">,</span> <span class="n">N.one_mem</span><span class="o">,</span> <span class="n">rfl</span><span class="o">⟩</span> <span class="n">symm</span> <span class="o">:=</span> <span class="k">fun</span> <span class="o">⟨</span><span class="n">w</span><span class="o">,</span> <span class="n">hw</span><span class="o">,</span> <span class="n">z</span><span class="o">,</span> <span class="n">hz</span><span class="o">,</span> <span class="n">h</span><span class="o">⟩</span> <span class="bp">↦</span> <span class="o">⟨</span><span class="n">z</span><span class="o">,</span> <span class="n">hz</span><span class="o">,</span> <span class="n">w</span><span class="o">,</span> <span class="n">hw</span><span class="o">,</span> <span class="n">h.symm</span><span class="o">⟩</span> <span class="n">trans</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="o">}</span> <span class="kd">instance</span> <span class="o">[</span><span class="n">CommMonoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">:</span> <span class="n">HasQuotient</span> <span class="n">M</span> <span class="o">(</span><span class="n">Submonoid</span> <span class="n">M</span><span class="o">)</span> <span class="n">where</span> <span class="n">quotient'</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">N</span> <span class="bp">↦</span> <span class="n">Quotient</span> <span class="n">N.Setoid</span> <span class="kd">def</span> <span class="n">QuotientMonoid.mk</span> <span class="o">[</span><span class="n">CommMonoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">(</span><span class="n">N</span> <span class="o">:</span> <span class="n">Submonoid</span> <span class="n">M</span><span class="o">)</span> <span class="o">:</span> <span class="n">M</span> <span class="bp">→</span> <span class="n">M</span> <span class="bp">⧸</span> <span class="n">N</span> <span class="o">:=</span> <span class="n">Quotient.mk</span> <span class="n">N.Setoid</span> <span class="kd">instance</span> <span class="o">[</span><span class="n">CommMonoid</span> <span class="n">M</span><span class="o">]</span> <span class="o">(</span><span class="n">N</span> <span class="o">:</span> <span class="n">Submonoid</span> <span class="n">M</span><span class="o">)</span> <span class="o">:</span> <span class="n">Monoid</span> <span class="o">(</span><span class="n">M</span> <span class="bp">⧸</span> <span class="n">N</span><span class="o">)</span> <span class="n">where</span> <span class="n">mul</span> <span class="o">:=</span> <span class="n">Quotient.map₂'</span> <span class="o">(</span><span class="bp">·</span> <span class="bp">*</span> <span class="bp">·</span><span class="o">)</span> <span class="o">(</span><span class="kd">by</span> <span class="gr">sorry</span> <span class="o">)</span> <span class="n">mul_assoc</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="n">one</span> <span class="o">:=</span> <span class="n">QuotientMonoid.mk</span> <span class="n">N</span> <span class="mi">1</span> <span class="n">one_mul</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="n">mul_one</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> </pre></div> </div> <p>-/</p> </section> </section> </div> </div> <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> <a href="C06_Structures.html" class="btn btn-neutral float-left" title="6. Structures" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> <a href="C08_Topology.html" class="btn btn-neutral float-right" title="8. Topology" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> </div> <hr/> <div role="contentinfo"> <p>© Copyright 2020, Jeremy Avigad, Kevin Buzzard, Robert Y. Lewis, Patrick Massot.</p> </div> Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. </footer> </div> </div> </section> </div> <script> jQuery(function () { SphinxRtdTheme.Navigation.enable(true); }); </script> </body> </html>
-
-
html/C08_Topology.html (new)
-
@@ -0,0 +1,1235 @@<!DOCTYPE html> <html class="writer-html5" lang="en" > <head> <meta charset="utf-8" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>8. Topology — Mathematics in Lean 0.1 documentation</title> <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> <link rel="stylesheet" href="_static/css/custom.css" type="text/css" /> <link rel="shortcut icon" href="_static/favicon.ico"/> <!--[if lt IE 9]> <script src="_static/js/html5shiv.min.js"></script> <![endif]--> <script src="_static/jquery.js"></script> <script src="_static/_sphinx_javascript_frameworks_compat.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script src="_static/doctools.js"></script> <script src="_static/sphinx_highlight.js"></script> <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> <script src="_static/js/theme.js"></script> <link rel="index" title="Index" href="genindex.html" /> <link rel="search" title="Search" href="search.html" /> <link rel="next" title="9. Differential Calculus" href="C09_Differential_Calculus.html" /> <link rel="prev" title="7. Hierarchies" href="C07_Hierarchies.html" /> </head> <body class="wy-body-for-nav"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search" > <a href="index.html" class="icon icon-home"> Mathematics in Lean </a> <div role="search"> <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> <ul class="current"> <li class="toctree-l1"><a class="reference internal" href="C01_Introduction.html">1. Introduction</a></li> <li class="toctree-l1"><a class="reference internal" href="C02_Basics.html">2. Basics</a></li> <li class="toctree-l1"><a class="reference internal" href="C03_Logic.html">3. Logic</a></li> <li class="toctree-l1"><a class="reference internal" href="C04_Sets_and_Functions.html">4. Sets and Functions</a></li> <li class="toctree-l1"><a class="reference internal" href="C05_Number_Theory.html">5. Number Theory</a></li> <li class="toctree-l1"><a class="reference internal" href="C06_Structures.html">6. Structures</a></li> <li class="toctree-l1"><a class="reference internal" href="C07_Hierarchies.html">7. Hierarchies</a></li> <li class="toctree-l1 current"><a class="current reference internal" href="#">8. Topology</a><ul> <li class="toctree-l2"><a class="reference internal" href="#filters">8.1. Filters</a></li> <li class="toctree-l2"><a class="reference internal" href="#metric-spaces">8.2. Metric spaces</a><ul> <li class="toctree-l3"><a class="reference internal" href="#convergence-and-continuity">8.2.1. Convergence and continuity</a></li> <li class="toctree-l3"><a class="reference internal" href="#balls-open-sets-and-closed-sets">8.2.2. Balls, open sets and closed sets</a></li> <li class="toctree-l3"><a class="reference internal" href="#compactness">8.2.3. Compactness</a></li> <li class="toctree-l3"><a class="reference internal" href="#uniformly-continuous-functions">8.2.4. Uniformly continuous functions</a></li> <li class="toctree-l3"><a class="reference internal" href="#completeness">8.2.5. Completeness</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#topological-spaces">8.3. Topological spaces</a><ul> <li class="toctree-l3"><a class="reference internal" href="#fundamentals">8.3.1. Fundamentals</a></li> <li class="toctree-l3"><a class="reference internal" href="#separation-and-countability">8.3.2. Separation and countability</a></li> <li class="toctree-l3"><a class="reference internal" href="#id5">8.3.3. Compactness</a></li> </ul> </li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="C09_Differential_Calculus.html">9. Differential Calculus</a></li> </ul> <ul> <li class="toctree-l1"><a class="reference internal" href="genindex.html">Index</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="index.html">Mathematics in Lean</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="Page navigation"> <ul class="wy-breadcrumbs"> <li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li> <li class="breadcrumb-item active"><span class="section-number">8. </span>Topology</li> <li class="wy-breadcrumbs-aside"> <a href="_sources/C08_Topology.rst.txt" rel="nofollow"> View page source</a> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <span class="target" id="topology"></span><section id="index-0"> <span id="id1"></span><h1><span class="section-number">8. </span>Topology<a class="headerlink" href="#index-0" title="Permalink to this heading"></a></h1> <p>Calculus is based on the concept of a function, which is used to model quantities that depend on one another. For example, it is common to study quantities that change over time. The notion of a <em>limit</em> is also fundamental. We may say that the limit of a function <span class="math notranslate nohighlight">\(f(x)\)</span> is a value <span class="math notranslate nohighlight">\(b\)</span> as <span class="math notranslate nohighlight">\(x\)</span> approaches a value <span class="math notranslate nohighlight">\(a\)</span>, or that <span class="math notranslate nohighlight">\(f(x)\)</span> <em>converges to</em> <span class="math notranslate nohighlight">\(b\)</span> as <span class="math notranslate nohighlight">\(x\)</span> approaches <span class="math notranslate nohighlight">\(a\)</span>. Equivalently, we may say that a <span class="math notranslate nohighlight">\(f(x)\)</span> approaches <span class="math notranslate nohighlight">\(a\)</span> as <span class="math notranslate nohighlight">\(x\)</span> approaches a value <span class="math notranslate nohighlight">\(b\)</span>, or that it <em>tends to</em> <span class="math notranslate nohighlight">\(b\)</span> as <span class="math notranslate nohighlight">\(x\)</span> tends to <span class="math notranslate nohighlight">\(a\)</span>. We have already begun to consider such notions in <a class="reference internal" href="C03_Logic.html#sequences-and-convergence"><span class="std std-numref">Section 3.6</span></a>.</p> <p><em>Topology</em> is the abstract study of limits and continuity. Having covered the essentials of formalization in Chapters <a class="reference internal" href="C02_Basics.html#basics"><span class="std std-numref">2</span></a> to <a class="reference internal" href="C06_Structures.html#structures"><span class="std std-numref">6</span></a>, in this chapter, we will explain how topological notions are formalized in mathlib. Not only do topological abstractions apply in much greater generality, but that also, somewhat paradoxically, make it easier to reason about limits and continuity in concrete instances.</p> <p>Topological notions build on quite a few layers of mathematical structure. The first layer is naive set theory, as described in <a class="reference internal" href="C04_Sets_and_Functions.html#sets-and-functions"><span class="std std-numref">Chapter 4</span></a>. The next layer is the theory of <em>filters</em>, which we will describe in <a class="reference internal" href="#filters"><span class="std std-numref">Section 8.1</span></a>. On top of that, we layer the theories of <em>topological spaces</em>, <em>metric spaces</em>, and a slightly more exotic intermediate notion called a <em>uniform space</em>.</p> <p>Whereas previous chapters relied on mathematical notions that were likely familiar to you, the notion of a filter less well known, even to many working mathematicians. The notion is essential, however, for formalizing mathematics effectively. Let us explain why. Let <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">ℝ</span> <span class="pre">→</span> <span class="pre">ℝ</span></code> be any function. We can consider the limit of <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span></code> as <code class="docutils literal notranslate"><span class="pre">x</span></code> approaches some value <code class="docutils literal notranslate"><span class="pre">x₀</span></code>, but we can also consider the limit of <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span></code> as <code class="docutils literal notranslate"><span class="pre">x</span></code> approaches infinity or negative infinity. We can moreover consider the limit of <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span></code> as <code class="docutils literal notranslate"><span class="pre">x</span></code> approaches <code class="docutils literal notranslate"><span class="pre">x₀</span></code> from the right, conventionally written <code class="docutils literal notranslate"><span class="pre">x₀⁺</span></code>, or from the left, written <code class="docutils literal notranslate"><span class="pre">x₀⁻</span></code>. There are variations where <code class="docutils literal notranslate"><span class="pre">x</span></code> approaches <code class="docutils literal notranslate"><span class="pre">x₀</span></code> or <code class="docutils literal notranslate"><span class="pre">x₀⁺</span></code> or <code class="docutils literal notranslate"><span class="pre">x₀⁻</span></code> but is not allowed to take on the value <code class="docutils literal notranslate"><span class="pre">x₀</span></code> itself. This results in at least eight ways that <code class="docutils literal notranslate"><span class="pre">x</span></code> can approach something. We can also restrict to rational values of <code class="docutils literal notranslate"><span class="pre">x</span></code> or place other constraints on the domain, but let’s stick to those 8 cases.</p> <p>We have a similar variety of options on the codomain: we can specify that <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span></code> approaches a value from the left or right, or that it approaches positive or negative infinity, and so on. For example, we may wish to say that <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span></code> tends to <code class="docutils literal notranslate"><span class="pre">+∞</span></code> when <code class="docutils literal notranslate"><span class="pre">x</span></code> tends to <code class="docutils literal notranslate"><span class="pre">x₀</span></code> from the right without being equal to <code class="docutils literal notranslate"><span class="pre">x₀</span></code>. This results in 64 different kinds of limit statements, and we haven’t even begun to deal with limits of sequences, as we did in <a class="reference internal" href="C03_Logic.html#sequences-and-convergence"><span class="std std-numref">Section 3.6</span></a>.</p> <p>The problem is compounded even further when it comes to the supporting lemmas. For instance, limits compose: if <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span></code> tends to <code class="docutils literal notranslate"><span class="pre">y₀</span></code> when <code class="docutils literal notranslate"><span class="pre">x</span></code> tends to <code class="docutils literal notranslate"><span class="pre">x₀</span></code> and <code class="docutils literal notranslate"><span class="pre">g</span> <span class="pre">y</span></code> tends to <code class="docutils literal notranslate"><span class="pre">z₀</span></code> when <code class="docutils literal notranslate"><span class="pre">y</span></code> tends to <code class="docutils literal notranslate"><span class="pre">y₀</span></code> then <code class="docutils literal notranslate"><span class="pre">g</span> <span class="pre">∘</span> <span class="pre">f</span> <span class="pre">x</span></code> tends to <code class="docutils literal notranslate"><span class="pre">z₀</span></code> when <code class="docutils literal notranslate"><span class="pre">x</span></code> tends to <code class="docutils literal notranslate"><span class="pre">x₀</span></code>. There are three notions of “tends to” at play here, each of which can be instantiated in any of the eight ways described in the previous paragraph. This results in 512 lemmas, a lot to have to add to a library! Informally, mathematicians generally prove two or three of these and simply note that the rest can be proved “in the same way.” Formalizing mathematics requires making the relevant notion of “sameness” fully explicit, and that is exactly what Bourbaki’s theory of filters manages to do.</p> <section id="filters"> <span id="index-1"></span><span id="id2"></span><h2><span class="section-number">8.1. </span>Filters<a class="headerlink" href="#filters" title="Permalink to this heading"></a></h2> <p>A <em>filter</em> on a type <code class="docutils literal notranslate"><span class="pre">X</span></code> is a collection of sets of <code class="docutils literal notranslate"><span class="pre">X</span></code> that satisfies three conditions that we will spell out below. The notion supports two related ideas:</p> <ul class="simple"> <li><p><em>limits</em>, including all the kinds of limits discussed above: finite and infinite limits of sequences, finite and infinite limits of functions at a point or at infinity, and so on.</p></li> <li><p><em>things happening eventually</em>, including things happening for large enough <code class="docutils literal notranslate"><span class="pre">n</span> <span class="pre">:</span> <span class="pre">ℕ</span></code>, or sufficiently near a point <code class="docutils literal notranslate"><span class="pre">x</span></code>, or for sufficiently close pairs of points, or almost everywhere in the sense of measure theory. Dually, filters can also express the idea of <em>things happening often</em>: for arbitrarily large <code class="docutils literal notranslate"><span class="pre">n</span></code>, at a point in any neighborhood of given a point, etc.</p></li> </ul> <p>The filters that correspond to these descriptions will be defined later in this section, but we can already name them:</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">(at_top</span> <span class="pre">:</span> <span class="pre">Filter</span> <span class="pre">ℕ)</span></code>, made of sets of <code class="docutils literal notranslate"><span class="pre">ℕ</span></code> containing <code class="docutils literal notranslate"><span class="pre">{n</span> <span class="pre">|</span> <span class="pre">n</span> <span class="pre">≥</span> <span class="pre">N}</span></code> for some <code class="docutils literal notranslate"><span class="pre">N</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">𝓝</span> <span class="pre">x</span></code>, made of neighborhoods of <code class="docutils literal notranslate"><span class="pre">x</span></code> in a topological space</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">𝓤</span> <span class="pre">X</span></code>, made of entourages of a uniform space (uniform spaces generalize metric spaces and topological groups)</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">μ.a_e</span></code> , made of sets whose complement has zero measure with respect to a measure <code class="docutils literal notranslate"><span class="pre">μ</span></code>.</p></li> </ul> <p>The general definition is as follows: a filter <code class="docutils literal notranslate"><span class="pre">F</span> <span class="pre">:</span> <span class="pre">Filter</span> <span class="pre">X</span></code> is a collection of sets <code class="docutils literal notranslate"><span class="pre">F.sets</span> <span class="pre">:</span> <span class="pre">Set</span> <span class="pre">(Set</span> <span class="pre">X)</span></code> satisfying the following:</p> <ul class="simple"> <li><p><code class="docutils literal notranslate"><span class="pre">F.univ_sets</span> <span class="pre">:</span> <span class="pre">univ</span> <span class="pre">∈</span> <span class="pre">F.sets</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">F.sets_of_superset</span> <span class="pre">:</span> <span class="pre">∀</span> <span class="pre">{U</span> <span class="pre">V},</span> <span class="pre">U</span> <span class="pre">∈</span> <span class="pre">F.sets</span> <span class="pre">→</span> <span class="pre">U</span> <span class="pre">⊆</span> <span class="pre">V</span> <span class="pre">→</span> <span class="pre">V</span> <span class="pre">∈</span> <span class="pre">F.sets</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">F.inter_sets</span> <span class="pre">:</span> <span class="pre">∀</span> <span class="pre">{U</span> <span class="pre">V},</span> <span class="pre">U</span> <span class="pre">∈</span> <span class="pre">F.sets</span> <span class="pre">→</span> <span class="pre">V</span> <span class="pre">∈</span> <span class="pre">F.sets</span> <span class="pre">→</span> <span class="pre">U</span> <span class="pre">∩</span> <span class="pre">V</span> <span class="pre">∈</span> <span class="pre">F.sets</span></code>.</p></li> </ul> <p>The first condition says that the set of all elements of <code class="docutils literal notranslate"><span class="pre">X</span></code> belongs to <code class="docutils literal notranslate"><span class="pre">F.sets</span></code>. The second condition says that if <code class="docutils literal notranslate"><span class="pre">U</span></code> belongs to <code class="docutils literal notranslate"><span class="pre">F.sets</span></code> then anything containing <code class="docutils literal notranslate"><span class="pre">U</span></code> also belongs to <code class="docutils literal notranslate"><span class="pre">F.sets</span></code>. The third condition says that <code class="docutils literal notranslate"><span class="pre">F.sets</span></code> is closed under finite intersections. In mathlib, a filter <code class="docutils literal notranslate"><span class="pre">F</span></code> is defined to be a structure bundling <code class="docutils literal notranslate"><span class="pre">F.sets</span></code> and its three properties, but the properties carry no additional data, and it is convenient to blur the distinction between <code class="docutils literal notranslate"><span class="pre">F</span></code> and <code class="docutils literal notranslate"><span class="pre">F.sets</span></code>. We therefore define <code class="docutils literal notranslate"><span class="pre">U</span> <span class="pre">∈</span> <span class="pre">F</span></code> to mean <code class="docutils literal notranslate"><span class="pre">U</span> <span class="pre">∈</span> <span class="pre">F.sets</span></code>. This explains why the word <code class="docutils literal notranslate"><span class="pre">sets</span></code> appears in the names of some lemmas that that mention <code class="docutils literal notranslate"><span class="pre">U</span> <span class="pre">∈</span> <span class="pre">F</span></code>.</p> <p>It may help to think of a filter as defining a notion of a “sufficiently large” set. The first condition then says that <code class="docutils literal notranslate"><span class="pre">univ</span></code> is sufficiently large, the second one says that a set containing a sufficiently large set is sufficiently large and the third one says that the intersection of two sufficiently large sets is sufficiently large.</p> <p>It may be even more useful to think of a filter on a type <code class="docutils literal notranslate"><span class="pre">X</span></code> as a generalized element of <code class="docutils literal notranslate"><span class="pre">Set</span> <span class="pre">X</span></code>. For instance, <code class="docutils literal notranslate"><span class="pre">at_top</span></code> is the “set of very large numbers” and <code class="docutils literal notranslate"><span class="pre">𝓝</span> <span class="pre">x₀</span></code> is the “set of points very close to <code class="docutils literal notranslate"><span class="pre">x₀</span></code>.” One manifestation of this view is that we can associate to any <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">:</span> <span class="pre">Set</span> <span class="pre">X</span></code> the so-called <em>principal filter</em> consisting of all sets that contain <code class="docutils literal notranslate"><span class="pre">s</span></code>. This definition is already in mathlib and has a notation <code class="docutils literal notranslate"><span class="pre">𝓟</span></code> (localized in the <code class="docutils literal notranslate"><span class="pre">Filter</span></code> namespace). For the purpose of demonstration, we ask you to take this opportunity to work out the definition here.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">principal</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">(</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">α</span><span class="o">)</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">α</span> <span class="n">where</span> <span class="n">sets</span> <span class="o">:=</span> <span class="o">{</span> <span class="n">t</span> <span class="bp">|</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="n">t</span> <span class="o">}</span> <span class="n">univ_sets</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">sets_of_superset</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">inter_sets</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>For our second example, we ask you to define the filter <code class="docutils literal notranslate"><span class="pre">at_top</span> <span class="pre">:</span> <span class="pre">Filter</span> <span class="pre">ℕ</span></code>. (We could use any type with a preorder instead of <code class="docutils literal notranslate"><span class="pre">ℕ</span></code>.)</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">ℕ</span> <span class="o">:=</span> <span class="o">{</span> <span class="n">sets</span> <span class="o">:=</span> <span class="o">{</span> <span class="n">s</span> <span class="bp">|</span> <span class="bp">∃</span> <span class="n">a</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">b</span><span class="o">,</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">b</span> <span class="bp">→</span> <span class="n">b</span> <span class="bp">∈</span> <span class="n">s</span> <span class="o">}</span> <span class="n">univ_sets</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">sets_of_superset</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">inter_sets</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="o">}</span> </pre></div> </div> <p>We can also directly define the filter <code class="docutils literal notranslate"><span class="pre">𝓝</span> <span class="pre">x</span></code> of neighborhoods of any <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">:</span> <span class="pre">ℝ</span></code>. In the real numbers, a neighborhood of <code class="docutils literal notranslate"><span class="pre">x</span></code> is a set containing an open interval <span class="math notranslate nohighlight">\((x_0 - \varepsilon, x_0 + \varepsilon)\)</span>, defined in mathlib as <code class="docutils literal notranslate"><span class="pre">Ioo</span> <span class="pre">(x₀</span> <span class="pre">-</span> <span class="pre">ε)</span> <span class="pre">(x₀</span> <span class="pre">+</span> <span class="pre">ε)</span></code>. (This is notion of a neighborhood is only a special case of a more general construction in mathlib.)</p> <p>With these examples, we can already define what is means for a function <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">Y</span></code> to converge to some <code class="docutils literal notranslate"><span class="pre">G</span> <span class="pre">:</span> <span class="pre">Filter</span> <span class="pre">Y</span></code> along some <code class="docutils literal notranslate"><span class="pre">F</span> <span class="pre">:</span> <span class="pre">Filter</span> <span class="pre">X</span></code>, as follows:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">Tendsto₁</span> <span class="o">{</span><span class="n">X</span> <span class="n">Y</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">)</span> <span class="o">(</span><span class="n">F</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">X</span><span class="o">)</span> <span class="o">(</span><span class="n">G</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">Y</span><span class="o">)</span> <span class="o">:=</span> <span class="bp">∀</span> <span class="n">V</span> <span class="bp">∈</span> <span class="n">G</span><span class="o">,</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">V</span> <span class="bp">∈</span> <span class="n">F</span> </pre></div> </div> <p>When <code class="docutils literal notranslate"><span class="pre">X</span></code> is <code class="docutils literal notranslate"><span class="pre">ℕ</span></code> and <code class="docutils literal notranslate"><span class="pre">Y</span></code> is <code class="docutils literal notranslate"><span class="pre">ℝ</span></code>, <code class="docutils literal notranslate"><span class="pre">Tendsto₁</span> <span class="pre">u</span> <span class="pre">at_top</span> <span class="pre">(𝓝</span> <span class="pre">x)</span></code> is equivalent to saying that the sequence <code class="docutils literal notranslate"><span class="pre">u</span> <span class="pre">:</span> <span class="pre">ℕ</span> <span class="pre">→</span> <span class="pre">ℝ</span></code> converges to the real number <code class="docutils literal notranslate"><span class="pre">x</span></code>. When both <code class="docutils literal notranslate"><span class="pre">X</span></code> and <code class="docutils literal notranslate"><span class="pre">Y</span></code> are <code class="docutils literal notranslate"><span class="pre">ℝ</span></code>, <code class="docutils literal notranslate"><span class="pre">Tendsto</span> <span class="pre">f</span> <span class="pre">(𝓝</span> <span class="pre">x₀)</span> <span class="pre">(𝓝</span> <span class="pre">y₀)</span></code> is equivalent to the familiar notion <span class="math notranslate nohighlight">\(\lim_{x \to x₀} f(x) = y₀\)</span>. All of the other kinds of limits mentioned in the introduction are also equivalent to instances of <code class="docutils literal notranslate"><span class="pre">Tendsto₁</span></code> for suitable choices of filters on the source and target.</p> <p>The notion <code class="docutils literal notranslate"><span class="pre">Tendsto₁</span></code> above is definitionally equivalent to the notion <code class="docutils literal notranslate"><span class="pre">Tendsto</span></code> that is defined in mathlib, but the latter is defined more abstractly. The problem with the definition of <code class="docutils literal notranslate"><span class="pre">Tendsto₁</span></code> is that it exposes a quantifier and elements of <code class="docutils literal notranslate"><span class="pre">G</span></code>, and it hides the intuition that we get by viewing filters as generalized sets. We can hide the quantifier <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">V</span></code> and make the intuition more salient by using more algebraic and set-theoretic machinery. The first ingredient is the <em>pushforward</em> operation <span class="math notranslate nohighlight">\(f_*\)</span> associated to any map <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">Y</span></code>, denoted <code class="docutils literal notranslate"><span class="pre">Filter.map</span> <span class="pre">f</span></code> in mathlib. Given a filter <code class="docutils literal notranslate"><span class="pre">F</span></code> on <code class="docutils literal notranslate"><span class="pre">X</span></code>, <code class="docutils literal notranslate"><span class="pre">Filter.map</span> <span class="pre">f</span> <span class="pre">F</span> <span class="pre">:</span> <span class="pre">Filter</span> <span class="pre">Y</span></code> is defined so that <code class="docutils literal notranslate"><span class="pre">V</span> <span class="pre">∈</span> <span class="pre">Filter.map</span> <span class="pre">f</span> <span class="pre">F</span> <span class="pre">↔</span> <span class="pre">f</span> <span class="pre">⁻¹'</span> <span class="pre">V</span> <span class="pre">∈</span> <span class="pre">F</span></code> holds definitionally. In this examples file we’ve opened the <code class="docutils literal notranslate"><span class="pre">Filter</span></code> namespace so that <code class="docutils literal notranslate"><span class="pre">Filter.map</span></code> can be written as <code class="docutils literal notranslate"><span class="pre">map</span></code>. This means that we can rewrite the definition of <code class="docutils literal notranslate"><span class="pre">Tendsto</span></code> using the order relation on <code class="docutils literal notranslate"><span class="pre">Filter</span> <span class="pre">Y</span></code>, which is reversed inclusion of the set of members. In other words, given <code class="docutils literal notranslate"><span class="pre">G</span> <span class="pre">H</span> <span class="pre">:</span> <span class="pre">Filter</span> <span class="pre">Y</span></code>, we have <code class="docutils literal notranslate"><span class="pre">G</span> <span class="pre">≤</span> <span class="pre">H</span> <span class="pre">↔</span> <span class="pre">∀</span> <span class="pre">V</span> <span class="pre">:</span> <span class="pre">Set</span> <span class="pre">Y,</span> <span class="pre">V</span> <span class="pre">∈</span> <span class="pre">H</span> <span class="pre">→</span> <span class="pre">V</span> <span class="pre">∈</span> <span class="pre">G</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">def</span> <span class="n">Tendsto₂</span> <span class="o">{</span><span class="n">X</span> <span class="n">Y</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">)</span> <span class="o">(</span><span class="n">F</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">X</span><span class="o">)</span> <span class="o">(</span><span class="n">G</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">Y</span><span class="o">)</span> <span class="o">:=</span> <span class="n">map</span> <span class="n">f</span> <span class="n">F</span> <span class="bp">≤</span> <span class="n">G</span> <span class="kd">example</span> <span class="o">{</span><span class="n">X</span> <span class="n">Y</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">)</span> <span class="o">(</span><span class="n">F</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">X</span><span class="o">)</span> <span class="o">(</span><span class="n">G</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">Y</span><span class="o">)</span> <span class="o">:</span> <span class="n">Tendsto₂</span> <span class="n">f</span> <span class="n">F</span> <span class="n">G</span> <span class="bp">↔</span> <span class="n">Tendsto₁</span> <span class="n">f</span> <span class="n">F</span> <span class="n">G</span> <span class="o">:=</span> <span class="n">Iff.rfl</span> </pre></div> </div> <p>It may seem that the order relation on filters is backward. But recall that we can view filters on <code class="docutils literal notranslate"><span class="pre">X</span></code> as generalized elements of <code class="docutils literal notranslate"><span class="pre">Set</span> <span class="pre">X</span></code>, via the inclusion of <code class="docutils literal notranslate"><span class="pre">𝓟</span> <span class="pre">:</span> <span class="pre">Set</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">Filter</span> <span class="pre">X</span></code> which maps any set <code class="docutils literal notranslate"><span class="pre">s</span></code> to the corresponding principal filter. This inclusion is order preserving, so the order relation on <code class="docutils literal notranslate"><span class="pre">Filter</span></code> can indeed be seen as the natural inclusion relation between generalized sets. In this analogy, pushforward is analogous to the direct image. And, indeed, <code class="docutils literal notranslate"><span class="pre">map</span> <span class="pre">f</span> <span class="pre">(𝓟</span> <span class="pre">s)</span> <span class="pre">=</span> <span class="pre">𝓟</span> <span class="pre">(f</span> <span class="pre">''</span> <span class="pre">s)</span></code>.</p> <p>We can now understand intuitively why a sequence <code class="docutils literal notranslate"><span class="pre">u</span> <span class="pre">:</span> <span class="pre">ℕ</span> <span class="pre">→</span> <span class="pre">ℝ</span></code> converges to a point <code class="docutils literal notranslate"><span class="pre">x₀</span></code> if and only if we have <code class="docutils literal notranslate"><span class="pre">map</span> <span class="pre">u</span> <span class="pre">at_top</span> <span class="pre">≤</span> <span class="pre">𝓝</span> <span class="pre">x₀</span></code>. The inequality means the “direct image under <code class="docutils literal notranslate"><span class="pre">u</span></code>” of “the set of very big natural numbers” is “included” in “the set of points very close to <code class="docutils literal notranslate"><span class="pre">x₀</span></code>.”</p> <p>As promised, the definition of <code class="docutils literal notranslate"><span class="pre">Tendsto₂</span></code> does not exhibit any quantifiers or sets. It also leverages the algebraic properties of the pushforward operation. First, each <code class="docutils literal notranslate"><span class="pre">Filter.map</span> <span class="pre">f</span></code> is monotone. And, second, <code class="docutils literal notranslate"><span class="pre">Filter.map</span></code> is compatible with composition.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="o">(</span><span class="bp">@</span><span class="n">Filter.map_mono</span> <span class="o">:</span> <span class="bp">∀</span> <span class="o">{</span><span class="n">α</span> <span class="n">β</span><span class="o">}</span> <span class="o">{</span><span class="n">m</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">β</span><span class="o">},</span> <span class="n">Monotone</span> <span class="o">(</span><span class="n">map</span> <span class="n">m</span><span class="o">))</span> <span class="k">#check</span> <span class="o">(</span><span class="bp">@</span><span class="n">Filter.map_map</span> <span class="o">:</span> <span class="bp">∀</span> <span class="o">{</span><span class="n">α</span> <span class="n">β</span> <span class="n">γ</span><span class="o">}</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">α</span><span class="o">}</span> <span class="o">{</span><span class="n">m</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">β</span><span class="o">}</span> <span class="o">{</span><span class="n">m'</span> <span class="o">:</span> <span class="n">β</span> <span class="bp">→</span> <span class="n">γ</span><span class="o">},</span> <span class="n">map</span> <span class="n">m'</span> <span class="o">(</span><span class="n">map</span> <span class="n">m</span> <span class="n">f</span><span class="o">)</span> <span class="bp">=</span> <span class="n">map</span> <span class="o">(</span><span class="n">m'</span> <span class="bp">∘</span> <span class="n">m</span><span class="o">)</span> <span class="n">f</span><span class="o">)</span> </pre></div> </div> <p>Together these two properties allow us to prove that limits compose, yielding in one shot all 256 variants of the composition lemma described in the introduction, and lots more. You can practice proving the following statement using either the definition of <code class="docutils literal notranslate"><span class="pre">Tendsto₁</span></code> in terms of the universal quantifier or the algebraic definition, together with the two lemmas above.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">X</span> <span class="n">Y</span> <span class="n">Z</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">{</span><span class="n">F</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">X</span><span class="o">}</span> <span class="o">{</span><span class="n">G</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">Y</span><span class="o">}</span> <span class="o">{</span><span class="n">H</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">Z</span><span class="o">}</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">}</span> <span class="o">{</span><span class="n">g</span> <span class="o">:</span> <span class="n">Y</span> <span class="bp">→</span> <span class="n">Z</span><span class="o">}</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">Tendsto₁</span> <span class="n">f</span> <span class="n">F</span> <span class="n">G</span><span class="o">)</span> <span class="o">(</span><span class="n">hg</span> <span class="o">:</span> <span class="n">Tendsto₁</span> <span class="n">g</span> <span class="n">G</span> <span class="n">H</span><span class="o">)</span> <span class="o">:</span> <span class="n">Tendsto₁</span> <span class="o">(</span><span class="n">g</span> <span class="bp">∘</span> <span class="n">f</span><span class="o">)</span> <span class="n">F</span> <span class="n">H</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>The pushforward construction uses a map to push filters from the map source to the map target. There also a <em>pullback</em> operation, <code class="docutils literal notranslate"><span class="pre">Filter.comap</span></code>, going in the other direction. This generalizes the preimage operation on sets. For any map <code class="docutils literal notranslate"><span class="pre">f</span></code>, <code class="docutils literal notranslate"><span class="pre">Filter.map</span> <span class="pre">f</span></code> and <code class="docutils literal notranslate"><span class="pre">Filter.comap</span> <span class="pre">f</span></code> form what is known as a <em>Galois connection</em>, which is to say, they satisfy</p> <blockquote> <div><p><code class="docutils literal notranslate"><span class="pre">Filter.map_le_iff_le_comap</span> <span class="pre">:</span> <span class="pre">Filter.map</span> <span class="pre">f</span> <span class="pre">F</span> <span class="pre">≤</span> <span class="pre">G</span> <span class="pre">↔</span> <span class="pre">F</span> <span class="pre">≤</span> <span class="pre">Filter.comap</span> <span class="pre">f</span> <span class="pre">G</span></code></p> </div></blockquote> <p>for every <code class="docutils literal notranslate"><span class="pre">F</span></code> and <code class="docutils literal notranslate"><span class="pre">G</span></code>. This operation could be used to provided another formulation of <code class="docutils literal notranslate"><span class="pre">Tendsto</span></code> that would be provably (but not definitionally) equivalent to the one in mathlib.</p> <p>The <code class="docutils literal notranslate"><span class="pre">comap</span></code> operation can be used to restrict filters to a subtype. For instance, suppose we have <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">ℝ</span> <span class="pre">→</span> <span class="pre">ℝ</span></code>, <code class="docutils literal notranslate"><span class="pre">x₀</span> <span class="pre">:</span> <span class="pre">ℝ</span></code> and <code class="docutils literal notranslate"><span class="pre">y₀</span> <span class="pre">:</span> <span class="pre">ℝ</span></code>, and suppose we want to state that <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span></code> approaches <code class="docutils literal notranslate"><span class="pre">y₀</span></code> when <code class="docutils literal notranslate"><span class="pre">x</span></code> approaches <code class="docutils literal notranslate"><span class="pre">x₀</span></code> within the rational numbers. We can pull the filter <code class="docutils literal notranslate"><span class="pre">𝓝</span> <span class="pre">x₀</span></code> back to <code class="docutils literal notranslate"><span class="pre">ℚ</span></code> using the coercion map <code class="docutils literal notranslate"><span class="pre">(↑)</span> <span class="pre">:</span> <span class="pre">ℚ</span> <span class="pre">→</span> <span class="pre">ℝ</span></code> and state <code class="docutils literal notranslate"><span class="pre">Tendsto</span> <span class="pre">(f</span> <span class="pre">∘</span> <span class="pre">(↑)</span> <span class="pre">:</span> <span class="pre">ℚ</span> <span class="pre">→</span> <span class="pre">ℝ)</span> <span class="pre">(comap</span> <span class="pre">(↑)</span> <span class="pre">(𝓝</span> <span class="pre">x₀))</span> <span class="pre">(𝓝</span> <span class="pre">y₀)</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">x₀</span> <span class="n">y₀</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="k">#check</span> <span class="n">comap</span> <span class="o">((</span><span class="bp">↑</span><span class="o">)</span> <span class="o">:</span> <span class="n">ℚ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">x₀</span><span class="o">)</span> <span class="k">#check</span> <span class="n">Tendsto</span> <span class="o">(</span><span class="n">f</span> <span class="bp">∘</span> <span class="o">(</span><span class="bp">↑</span><span class="o">))</span> <span class="o">(</span><span class="n">comap</span> <span class="o">((</span><span class="bp">↑</span><span class="o">)</span> <span class="o">:</span> <span class="n">ℚ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">x₀</span><span class="o">))</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">y₀</span><span class="o">)</span> </pre></div> </div> <p>The pullback operation is also compatible with composition, but it is <em>contravariant</em>, which is to say, it reverses the order of the arguments.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">section</span> <span class="kd">variable</span> <span class="o">{</span><span class="n">α</span> <span class="n">β</span> <span class="n">γ</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">(</span><span class="n">F</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">α</span><span class="o">)</span> <span class="o">{</span><span class="n">m</span> <span class="o">:</span> <span class="n">γ</span> <span class="bp">→</span> <span class="n">β</span><span class="o">}</span> <span class="o">{</span><span class="n">n</span> <span class="o">:</span> <span class="n">β</span> <span class="bp">→</span> <span class="n">α</span><span class="o">}</span> <span class="k">#check</span> <span class="o">(</span><span class="n">comap_comap</span> <span class="o">:</span> <span class="n">comap</span> <span class="n">m</span> <span class="o">(</span><span class="n">comap</span> <span class="n">n</span> <span class="n">F</span><span class="o">)</span> <span class="bp">=</span> <span class="n">comap</span> <span class="o">(</span><span class="n">n</span> <span class="bp">∘</span> <span class="n">m</span><span class="o">)</span> <span class="n">F</span><span class="o">)</span> <span class="kd">end</span> </pre></div> </div> <p>Let’s now shift attention to the plane <code class="docutils literal notranslate"><span class="pre">ℝ</span> <span class="pre">×</span> <span class="pre">ℝ</span></code> and try to understand how the neighborhoods of a point <code class="docutils literal notranslate"><span class="pre">(x₀,</span> <span class="pre">y₀)</span></code> are related to <code class="docutils literal notranslate"><span class="pre">𝓝</span> <span class="pre">x₀</span></code> and <code class="docutils literal notranslate"><span class="pre">𝓝</span> <span class="pre">y₀</span></code>. There is a product operation <code class="docutils literal notranslate"><span class="pre">Filter.prod</span> <span class="pre">:</span> <span class="pre">Filter</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">Filter</span> <span class="pre">Y</span> <span class="pre">→</span> <span class="pre">Filter</span> <span class="pre">(X</span> <span class="pre">×</span> <span class="pre">Y)</span></code>, denoted by <code class="docutils literal notranslate"><span class="pre">×ˢ</span></code>, which answers this question:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="bp">𝓝</span> <span class="o">(</span><span class="n">x₀</span><span class="o">,</span> <span class="n">y₀</span><span class="o">)</span> <span class="bp">=</span> <span class="bp">𝓝</span> <span class="n">x₀</span> <span class="bp">×ˢ</span> <span class="bp">𝓝</span> <span class="n">y₀</span> <span class="o">:=</span> <span class="n">nhds_prod_eq</span> </pre></div> </div> <p>The product operation is defined in terms of the pullback operation and the <code class="docutils literal notranslate"><span class="pre">inf</span></code> operation:</p> <blockquote> <div><p><code class="docutils literal notranslate"><span class="pre">F</span> <span class="pre">×ˢ</span> <span class="pre">G</span> <span class="pre">=</span> <span class="pre">(comap</span> <span class="pre">prod.fst</span> <span class="pre">F)</span> <span class="pre">⊓</span> <span class="pre">(comap</span> <span class="pre">prod.snd</span> <span class="pre">G)</span></code>.</p> </div></blockquote> <p>Here the <code class="docutils literal notranslate"><span class="pre">inf</span></code> operation refers to the lattice structure on <code class="docutils literal notranslate"><span class="pre">filter</span> <span class="pre">X</span></code> for any type <code class="docutils literal notranslate"><span class="pre">X</span></code>, whereby <code class="docutils literal notranslate"><span class="pre">F</span> <span class="pre">⊓</span> <span class="pre">G</span></code> is the greatest filter that is smaller than both <code class="docutils literal notranslate"><span class="pre">F</span></code> and <code class="docutils literal notranslate"><span class="pre">G</span></code>. Thus the <code class="docutils literal notranslate"><span class="pre">inf</span></code> operation generalizes the notion of the intersection of sets.</p> <p>A lot of proofs in mathlib use all of the aforementioned structure (<code class="docutils literal notranslate"><span class="pre">map</span></code>, <code class="docutils literal notranslate"><span class="pre">comap</span></code>, <code class="docutils literal notranslate"><span class="pre">inf</span></code>, <code class="docutils literal notranslate"><span class="pre">sup</span></code>, and <code class="docutils literal notranslate"><span class="pre">prod</span></code>) to give algebraic proofs about convergence without ever referring to members of filters. You can practice doing this in a proof of the following lemma, unfolding the definition of <code class="docutils literal notranslate"><span class="pre">Tendsto</span></code> and <code class="docutils literal notranslate"><span class="pre">Filter.prod</span></code> if needed.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="n">le_inf_iff</span> <span class="kd">example</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℝ</span> <span class="bp">×</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">x₀</span> <span class="n">y₀</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">Tendsto</span> <span class="n">f</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="o">(</span><span class="n">x₀</span><span class="o">,</span> <span class="n">y₀</span><span class="o">))</span> <span class="bp">↔</span> <span class="n">Tendsto</span> <span class="o">(</span><span class="n">Prod.fst</span> <span class="bp">∘</span> <span class="n">f</span><span class="o">)</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">x₀</span><span class="o">)</span> <span class="bp">∧</span> <span class="n">Tendsto</span> <span class="o">(</span><span class="n">Prod.snd</span> <span class="bp">∘</span> <span class="n">f</span><span class="o">)</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">y₀</span><span class="o">)</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>The ordered type <code class="docutils literal notranslate"><span class="pre">filter</span> <span class="pre">X</span></code> is actually a <em>complete</em> lattice, which is to say, there is a bottom element, there is a top element, and every set of filters on <code class="docutils literal notranslate"><span class="pre">X</span></code> has an <code class="docutils literal notranslate"><span class="pre">Inf</span></code> and a <code class="docutils literal notranslate"><span class="pre">Sup</span></code>.</p> <p>Note that given the second property in the definition of a filter (if <code class="docutils literal notranslate"><span class="pre">U</span></code> belongs to <code class="docutils literal notranslate"><span class="pre">F</span></code> then anything larger than <code class="docutils literal notranslate"><span class="pre">U</span></code> also belongs to <code class="docutils literal notranslate"><span class="pre">F</span></code>), the first property (the set of all inhabitants of <code class="docutils literal notranslate"><span class="pre">X</span></code> belongs to <code class="docutils literal notranslate"><span class="pre">F</span></code>) is equivalent to the property that <code class="docutils literal notranslate"><span class="pre">F</span></code> is not the empty collection of sets. This shouldn’t be confused with the more subtle question as to whether the empty set is an <em>element</em> of <code class="docutils literal notranslate"><span class="pre">F</span></code>. The definition of a filter does not prohibit <code class="docutils literal notranslate"><span class="pre">∅</span> <span class="pre">∈</span> <span class="pre">F</span></code>, but if the empty set is in <code class="docutils literal notranslate"><span class="pre">F</span></code> then every set is in <code class="docutils literal notranslate"><span class="pre">F</span></code>, which is to say, <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">U</span> <span class="pre">:</span> <span class="pre">Set</span> <span class="pre">X,</span> <span class="pre">U</span> <span class="pre">∈</span> <span class="pre">F</span></code>. In this case, <code class="docutils literal notranslate"><span class="pre">F</span></code> is a rather trivial filter, which is precisely the bottom element of the complete lattice <code class="docutils literal notranslate"><span class="pre">filter</span> <span class="pre">X</span></code>. This contrasts with the definition of filters in Bourbaki, which doesn’t allow filters containing the empty set.</p> <p>Because we include the trivial filter in our definition, we sometimes need to explicitly assume nontriviality in some lemmas. In return, however, the theory has nicer global properties. We have already seen that including the trivial filter gives us a bottom element. It also allows us to define <code class="docutils literal notranslate"><span class="pre">principal</span> <span class="pre">:</span> <span class="pre">Set</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">Filter</span> <span class="pre">X</span></code>, which maps <code class="docutils literal notranslate"><span class="pre">∅</span></code> to <code class="docutils literal notranslate"><span class="pre">⊥</span></code>, without adding a precondition to rule out the empty set. And it allows us to define the pullback operation without a precondition as well. Indeed, it can happen that <code class="docutils literal notranslate"><span class="pre">comap</span> <span class="pre">f</span> <span class="pre">F</span> <span class="pre">=</span> <span class="pre">⊥</span></code> although <code class="docutils literal notranslate"><span class="pre">F</span> <span class="pre">≠</span> <span class="pre">⊥</span></code>. For instance, given <code class="docutils literal notranslate"><span class="pre">x₀</span> <span class="pre">:</span> <span class="pre">ℝ</span></code> and <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">:</span> <span class="pre">Set</span> <span class="pre">ℝ</span></code>, the pullback of <code class="docutils literal notranslate"><span class="pre">𝓝</span> <span class="pre">x₀</span></code> under the coercion from the subtype corresponding to <code class="docutils literal notranslate"><span class="pre">s</span></code> is nontrivial if and only if <code class="docutils literal notranslate"><span class="pre">x₀</span></code> belongs to the closure of <code class="docutils literal notranslate"><span class="pre">s</span></code>.</p> <p>In order to manage lemmas that do need to assume some filter is nontrivial, mathlib has a type class <code class="docutils literal notranslate"><span class="pre">Filter.ne_bot</span></code>, and the library has lemmas that assume <code class="docutils literal notranslate"><span class="pre">(F</span> <span class="pre">:</span> <span class="pre">Filter</span> <span class="pre">X)</span> <span class="pre">[F.ne_bot]</span></code>. The instance database knows, for example, that <code class="docutils literal notranslate"><span class="pre">(at_top</span> <span class="pre">:</span> <span class="pre">Filter</span> <span class="pre">ℕ).ne_bot</span></code>, and it knows that pushing forward a nontrivial filter gives a nontrivial filter. As a result, a lemma assuming <code class="docutils literal notranslate"><span class="pre">[F.ne_bot]</span></code> will automatically apply to <code class="docutils literal notranslate"><span class="pre">map</span> <span class="pre">u</span> <span class="pre">at_top</span></code> for any sequence <code class="docutils literal notranslate"><span class="pre">u</span></code>.</p> <p>Our tour of the algebraic properties of filters and their relation to limits is essentially done, but we have not yet justified our claim to have recaptured the usual limit notions. Superficially, it may seem that <code class="docutils literal notranslate"><span class="pre">Tendsto</span> <span class="pre">u</span> <span class="pre">at_top</span> <span class="pre">(𝓝</span> <span class="pre">x₀)</span></code> is stronger than the notion of convergence defined in <a class="reference internal" href="C03_Logic.html#sequences-and-convergence"><span class="std std-numref">Section 3.6</span></a> because we ask that <em>every</em> neighborhood of <code class="docutils literal notranslate"><span class="pre">x₀</span></code> has a preimage belonging to <code class="docutils literal notranslate"><span class="pre">at_top</span></code>, whereas the usual definition only requires this for the standard neighborhoods <code class="docutils literal notranslate"><span class="pre">Ioo</span> <span class="pre">(x₀</span> <span class="pre">-</span> <span class="pre">ε)</span> <span class="pre">(x₀</span> <span class="pre">+</span> <span class="pre">ε)</span></code>. The key is that, by definition, every neighborhood contains such a standard one. This observation leads to the notion of a <em>filter basis</em>.</p> <p>Given <code class="docutils literal notranslate"><span class="pre">F</span> <span class="pre">:</span> <span class="pre">Filter</span> <span class="pre">X</span></code>, a family of sets <cite>s : ι → Set X</cite> is a basis for <code class="docutils literal notranslate"><span class="pre">F</span></code> if for every set <code class="docutils literal notranslate"><span class="pre">U</span></code>, we have <code class="docutils literal notranslate"><span class="pre">U</span> <span class="pre">∈</span> <span class="pre">F</span></code> if and only if it contains some <code class="docutils literal notranslate"><span class="pre">s</span> <span class="pre">i</span></code>. In other words, formally speaking, <code class="docutils literal notranslate"><span class="pre">s</span></code> is a basis if it satisfies <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">U</span> <span class="pre">:</span> <span class="pre">Set</span> <span class="pre">X,</span> <span class="pre">U</span> <span class="pre">∈</span> <span class="pre">F</span> <span class="pre">↔</span> <span class="pre">∃</span> <span class="pre">i,</span> <span class="pre">s</span> <span class="pre">i</span> <span class="pre">⊆</span> <span class="pre">U</span></code>. It is even more flexible to consider a predicate on <code class="docutils literal notranslate"><span class="pre">ι</span></code> that selects only some of the values <code class="docutils literal notranslate"><span class="pre">i</span></code> in the indexing type. In the case of <code class="docutils literal notranslate"><span class="pre">𝓝</span> <span class="pre">x₀</span></code>, we want <code class="docutils literal notranslate"><span class="pre">ι</span></code> to be <code class="docutils literal notranslate"><span class="pre">ℝ</span></code>, we write <code class="docutils literal notranslate"><span class="pre">ε</span></code> for <code class="docutils literal notranslate"><span class="pre">i</span></code>, and the predicate should select the positive values of <code class="docutils literal notranslate"><span class="pre">ε</span></code>. So the fact that the sets <code class="docutils literal notranslate"><span class="pre">Ioo</span>  <span class="pre">(x₀</span> <span class="pre">-</span> <span class="pre">ε)</span> <span class="pre">(x₀</span> <span class="pre">+</span> <span class="pre">ε)</span></code> form a basis for the neighborhood topology on <code class="docutils literal notranslate"><span class="pre">ℝ</span></code> is stated as follows:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">x₀</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">HasBasis</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">x₀</span><span class="o">)</span> <span class="o">(</span><span class="k">fun</span> <span class="n">ε</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">=></span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">ε</span><span class="o">)</span> <span class="k">fun</span> <span class="n">ε</span> <span class="bp">=></span> <span class="n">Ioo</span> <span class="o">(</span><span class="n">x₀</span> <span class="bp">-</span> <span class="n">ε</span><span class="o">)</span> <span class="o">(</span><span class="n">x₀</span> <span class="bp">+</span> <span class="n">ε</span><span class="o">)</span> <span class="o">:=</span> <span class="n">nhds_basis_Ioo_pos</span> <span class="n">x₀</span> </pre></div> </div> <p>There is also a nice basis for the filter <code class="docutils literal notranslate"><span class="pre">at_top</span></code>. The lemma <code class="docutils literal notranslate"><span class="pre">Filter.has_basis.tendsto_iff</span></code> allows us to reformulate a statement of the form <code class="docutils literal notranslate"><span class="pre">Tendsto</span> <span class="pre">f</span> <span class="pre">F</span> <span class="pre">G</span></code> given bases for <code class="docutils literal notranslate"><span class="pre">F</span></code> and <code class="docutils literal notranslate"><span class="pre">G</span></code>. Putting these pieces together gives us essentially the notion of convergence that we used in <a class="reference internal" href="C03_Logic.html#sequences-and-convergence"><span class="std std-numref">Section 3.6</span></a>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">u</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">x₀</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">Tendsto</span> <span class="n">u</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">x₀</span><span class="o">)</span> <span class="bp">↔</span> <span class="bp">∀</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">N</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">n</span> <span class="bp">≥</span> <span class="n">N</span><span class="o">,</span> <span class="n">u</span> <span class="n">n</span> <span class="bp">∈</span> <span class="n">Ioo</span> <span class="o">(</span><span class="n">x₀</span> <span class="bp">-</span> <span class="n">ε</span><span class="o">)</span> <span class="o">(</span><span class="n">x₀</span> <span class="bp">+</span> <span class="n">ε</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="k">have</span> <span class="o">:</span> <span class="n">atTop.HasBasis</span> <span class="o">(</span><span class="k">fun</span> <span class="n">_</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">=></span> <span class="n">True</span><span class="o">)</span> <span class="n">Ici</span> <span class="o">:=</span> <span class="n">atTop_basis</span> <span class="n">rw</span> <span class="o">[</span><span class="n">this.tendsto_iff</span> <span class="o">(</span><span class="n">nhds_basis_Ioo_pos</span> <span class="n">x₀</span><span class="o">)]</span> <span class="n">simp</span> </pre></div> </div> <p>We now show how filters facilitate working with properties that hold for sufficiently large numbers or for points that are sufficiently close to a given point. In <a class="reference internal" href="C03_Logic.html#sequences-and-convergence"><span class="std std-numref">Section 3.6</span></a>, we were often faced with the situation where we knew that some property <code class="docutils literal notranslate"><span class="pre">P</span> <span class="pre">n</span></code> holds for sufficiently large <code class="docutils literal notranslate"><span class="pre">n</span></code> and that some other property <code class="docutils literal notranslate"><span class="pre">Q</span> <span class="pre">n</span></code> holds for sufficiently large <code class="docutils literal notranslate"><span class="pre">n</span></code>. Using <code class="docutils literal notranslate"><span class="pre">cases</span></code> twice gave us <code class="docutils literal notranslate"><span class="pre">N_P</span></code> and <code class="docutils literal notranslate"><span class="pre">N_Q</span></code> satisfying <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">n</span> <span class="pre">≥</span> <span class="pre">N_P,</span> <span class="pre">P</span> <span class="pre">n</span></code> and <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">n</span> <span class="pre">≥</span> <span class="pre">N_Q,</span> <span class="pre">Q</span> <span class="pre">n</span></code>. Using <code class="docutils literal notranslate"><span class="pre">set</span> <span class="pre">N</span> <span class="pre">:=</span> <span class="pre">max</span> <span class="pre">N_P</span> <span class="pre">N_Q</span></code>, we could eventually prove <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">n</span> <span class="pre">≥</span> <span class="pre">N,</span> <span class="pre">P</span> <span class="pre">n</span> <span class="pre">∧</span> <span class="pre">Q</span> <span class="pre">n</span></code>. Doing this repeatedly becomes tiresome.</p> <p>We can do better by noting that the statement “<code class="docutils literal notranslate"><span class="pre">P</span> <span class="pre">n</span></code> and <code class="docutils literal notranslate"><span class="pre">Q</span> <span class="pre">n</span></code> hold for large enough <code class="docutils literal notranslate"><span class="pre">n</span></code>” means that we have <code class="docutils literal notranslate"><span class="pre">{n</span> <span class="pre">|</span> <span class="pre">P</span> <span class="pre">n}</span> <span class="pre">∈</span> <span class="pre">at_top</span></code> and <code class="docutils literal notranslate"><span class="pre">{n</span> <span class="pre">|</span> <span class="pre">Q</span> <span class="pre">n}</span> <span class="pre">∈</span> <span class="pre">at_top</span></code>. The fact that <code class="docutils literal notranslate"><span class="pre">at_top</span></code> is a filter implies that the intersection of two elements of <code class="docutils literal notranslate"><span class="pre">at_top</span></code> is again in <code class="docutils literal notranslate"><span class="pre">at_top</span></code>, so we have <code class="docutils literal notranslate"><span class="pre">{n</span> <span class="pre">|</span> <span class="pre">P</span> <span class="pre">n</span> <span class="pre">∧</span> <span class="pre">Q</span> <span class="pre">n}</span> <span class="pre">∈</span> <span class="pre">at_top</span></code>. Writing <code class="docutils literal notranslate"><span class="pre">{n</span> <span class="pre">|</span> <span class="pre">P</span> <span class="pre">n}</span> <span class="pre">∈</span> <span class="pre">at_top</span></code> is unpleasant, but we can use the more suggestive notation <code class="docutils literal notranslate"><span class="pre">∀ᶠ</span> <span class="pre">n</span> <span class="pre">in</span> <span class="pre">at_top,</span> <span class="pre">P</span> <span class="pre">n</span></code>. Here the superscripted <code class="docutils literal notranslate"><span class="pre">f</span></code> stands for “Filter.” You can think of the notation as saying that for all <code class="docutils literal notranslate"><span class="pre">n</span></code> in the “set of very large numbers,” <code class="docutils literal notranslate"><span class="pre">P</span> <span class="pre">n</span></code> holds. The <code class="docutils literal notranslate"><span class="pre">∀ᶠ</span></code> notation stands for <code class="docutils literal notranslate"><span class="pre">Filter.Eventually</span></code>, and the lemma <code class="docutils literal notranslate"><span class="pre">Filter.Eventually.and</span></code> uses the intersection property of filters to do what we just described:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">P</span> <span class="n">Q</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="kt">Prop</span><span class="o">)</span> <span class="o">(</span><span class="n">hP</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">n</span> <span class="k">in</span> <span class="n">atTop</span><span class="o">,</span> <span class="n">P</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">hQ</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">n</span> <span class="k">in</span> <span class="n">atTop</span><span class="o">,</span> <span class="n">Q</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">n</span> <span class="k">in</span> <span class="n">atTop</span><span class="o">,</span> <span class="n">P</span> <span class="n">n</span> <span class="bp">∧</span> <span class="n">Q</span> <span class="n">n</span> <span class="o">:=</span> <span class="n">hP.and</span> <span class="n">hQ</span> </pre></div> </div> <p>This notation is so convenient and intuitive that we also have specializations when <code class="docutils literal notranslate"><span class="pre">P</span></code> is an equality or inequality statement. For example, let <code class="docutils literal notranslate"><span class="pre">u</span></code> and <code class="docutils literal notranslate"><span class="pre">v</span></code> be two sequences of real numbers, and let us show that if <code class="docutils literal notranslate"><span class="pre">u</span> <span class="pre">n</span></code> and <code class="docutils literal notranslate"><span class="pre">v</span> <span class="pre">n</span></code> coincide for sufficiently large <code class="docutils literal notranslate"><span class="pre">n</span></code> then <code class="docutils literal notranslate"><span class="pre">u</span></code> tends to <code class="docutils literal notranslate"><span class="pre">x₀</span></code> if and only if <code class="docutils literal notranslate"><span class="pre">v</span></code> tends to <code class="docutils literal notranslate"><span class="pre">x₀</span></code>. First we’ll use the generic <code class="docutils literal notranslate"><span class="pre">Eventually</span></code> and then the one specialized for the equality predicate, <code class="docutils literal notranslate"><span class="pre">Eventually_eq</span></code>. The two statements are definitionally equivalent so the same proof work in both cases.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">u</span> <span class="n">v</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">n</span> <span class="k">in</span> <span class="n">atTop</span><span class="o">,</span> <span class="n">u</span> <span class="n">n</span> <span class="bp">=</span> <span class="n">v</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">x₀</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">Tendsto</span> <span class="n">u</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">x₀</span><span class="o">)</span> <span class="bp">↔</span> <span class="n">Tendsto</span> <span class="n">v</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">x₀</span><span class="o">)</span> <span class="o">:=</span> <span class="n">tendsto_congr'</span> <span class="n">h</span> <span class="kd">example</span> <span class="o">(</span><span class="n">u</span> <span class="n">v</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">u</span> <span class="bp">=ᶠ</span><span class="o">[</span><span class="n">atTop</span><span class="o">]</span> <span class="n">v</span><span class="o">)</span> <span class="o">(</span><span class="n">x₀</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">Tendsto</span> <span class="n">u</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">x₀</span><span class="o">)</span> <span class="bp">↔</span> <span class="n">Tendsto</span> <span class="n">v</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">x₀</span><span class="o">)</span> <span class="o">:=</span> <span class="n">tendsto_congr'</span> <span class="n">h</span> </pre></div> </div> <p>It is instructive to review the definition of filters in terms of <code class="docutils literal notranslate"><span class="pre">Eventually</span></code>. Given <code class="docutils literal notranslate"><span class="pre">F</span> <span class="pre">:</span> <span class="pre">Filter</span> <span class="pre">X</span></code>, for any predicates <code class="docutils literal notranslate"><span class="pre">P</span></code> and <code class="docutils literal notranslate"><span class="pre">Q</span></code> on <code class="docutils literal notranslate"><span class="pre">X</span></code>,</p> <ul class="simple"> <li><p>the condition <code class="docutils literal notranslate"><span class="pre">univ</span> <span class="pre">∈</span> <span class="pre">F</span></code> ensures <code class="docutils literal notranslate"><span class="pre">(∀</span> <span class="pre">x,</span> <span class="pre">P</span> <span class="pre">x)</span> <span class="pre">→</span> <span class="pre">∀ᶠ</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">F,</span> <span class="pre">P</span> <span class="pre">x</span></code>,</p></li> <li><p>the condition <code class="docutils literal notranslate"><span class="pre">U</span> <span class="pre">∈</span> <span class="pre">F</span> <span class="pre">→</span> <span class="pre">U</span> <span class="pre">⊆</span> <span class="pre">V</span> <span class="pre">→</span> <span class="pre">V</span> <span class="pre">∈</span> <span class="pre">F</span></code> ensures <code class="docutils literal notranslate"><span class="pre">(∀ᶠ</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">F,</span> <span class="pre">P</span> <span class="pre">x)</span> <span class="pre">→</span> <span class="pre">(∀</span> <span class="pre">x,</span> <span class="pre">P</span> <span class="pre">x</span> <span class="pre">→</span> <span class="pre">Q</span> <span class="pre">x)</span> <span class="pre">→</span> <span class="pre">∀ᶠ</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">F,</span> <span class="pre">Q</span> <span class="pre">x</span></code>, and</p></li> <li><p>the condition <code class="docutils literal notranslate"><span class="pre">U</span> <span class="pre">∈</span> <span class="pre">F</span> <span class="pre">→</span> <span class="pre">V</span> <span class="pre">∈</span> <span class="pre">F</span> <span class="pre">→</span> <span class="pre">U</span> <span class="pre">∩</span> <span class="pre">V</span> <span class="pre">∈</span> <span class="pre">F</span></code> ensures <code class="docutils literal notranslate"><span class="pre">(∀ᶠ</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">F,</span> <span class="pre">P</span> <span class="pre">x)</span> <span class="pre">→</span> <span class="pre">(∀ᶠ</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">F,</span> <span class="pre">Q</span> <span class="pre">x)</span> <span class="pre">→</span> <span class="pre">∀ᶠ</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">F,</span> <span class="pre">P</span> <span class="pre">x</span> <span class="pre">∧</span> <span class="pre">Q</span> <span class="pre">x</span></code>.</p></li> </ul> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="bp">@</span><span class="n">eventually_of_forall</span> <span class="k">#check</span> <span class="bp">@</span><span class="n">Eventually.mono</span> <span class="k">#check</span> <span class="bp">@</span><span class="n">Eventually.and</span> </pre></div> </div> <p>The second item, corresponding to <code class="docutils literal notranslate"><span class="pre">eventually.mono</span></code>, supports nice ways of using filters, especially when combined with <code class="docutils literal notranslate"><span class="pre">eventually.and</span></code>. The <code class="docutils literal notranslate"><span class="pre">filter_upwards</span></code> tactic allows us to combine them. Compare:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">P</span> <span class="n">Q</span> <span class="n">R</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="kt">Prop</span><span class="o">)</span> <span class="o">(</span><span class="n">hP</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">n</span> <span class="k">in</span> <span class="n">atTop</span><span class="o">,</span> <span class="n">P</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">hQ</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">n</span> <span class="k">in</span> <span class="n">atTop</span><span class="o">,</span> <span class="n">Q</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">hR</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">n</span> <span class="k">in</span> <span class="n">atTop</span><span class="o">,</span> <span class="n">P</span> <span class="n">n</span> <span class="bp">∧</span> <span class="n">Q</span> <span class="n">n</span> <span class="bp">→</span> <span class="n">R</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">n</span> <span class="k">in</span> <span class="n">atTop</span><span class="o">,</span> <span class="n">R</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="o">(</span><span class="n">hP.and</span> <span class="o">(</span><span class="n">hQ.and</span> <span class="n">hR</span><span class="o">))</span><span class="bp">.</span><span class="n">mono</span> <span class="n">rintro</span> <span class="n">n</span> <span class="o">⟨</span><span class="n">h</span><span class="o">,</span> <span class="n">h'</span><span class="o">,</span> <span class="n">h''</span><span class="o">⟩</span> <span class="n">exact</span> <span class="n">h''</span> <span class="o">⟨</span><span class="n">h</span><span class="o">,</span> <span class="n">h'</span><span class="o">⟩</span> <span class="kd">example</span> <span class="o">(</span><span class="n">P</span> <span class="n">Q</span> <span class="n">R</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="kt">Prop</span><span class="o">)</span> <span class="o">(</span><span class="n">hP</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">n</span> <span class="k">in</span> <span class="n">atTop</span><span class="o">,</span> <span class="n">P</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">hQ</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">n</span> <span class="k">in</span> <span class="n">atTop</span><span class="o">,</span> <span class="n">Q</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">hR</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">n</span> <span class="k">in</span> <span class="n">atTop</span><span class="o">,</span> <span class="n">P</span> <span class="n">n</span> <span class="bp">∧</span> <span class="n">Q</span> <span class="n">n</span> <span class="bp">→</span> <span class="n">R</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">n</span> <span class="k">in</span> <span class="n">atTop</span><span class="o">,</span> <span class="n">R</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">filter_upwards</span> <span class="o">[</span><span class="n">hP</span><span class="o">,</span> <span class="n">hQ</span><span class="o">,</span> <span class="n">hR</span><span class="o">]</span> <span class="n">intro</span> <span class="n">n</span> <span class="n">h</span> <span class="n">h'</span> <span class="n">h''</span> <span class="n">exact</span> <span class="n">h''</span> <span class="o">⟨</span><span class="n">h</span><span class="o">,</span> <span class="n">h'</span><span class="o">⟩</span> </pre></div> </div> <p>Readers who know about measure theory will note that the filter <code class="docutils literal notranslate"><span class="pre">μ.ae</span></code> of sets whose complement has measure zero (aka “the set consisting of almost every point”) is not very useful as the source or target of <code class="docutils literal notranslate"><span class="pre">Tendsto</span></code>, but it can be conveniently used with <code class="docutils literal notranslate"><span class="pre">eventually</span></code> to say that a property holds for almost every point.</p> <p>There is a dual version of <code class="docutils literal notranslate"><span class="pre">∀ᶠ</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">F,</span> <span class="pre">P</span> <span class="pre">x</span></code>, which is occasionally useful: <code class="docutils literal notranslate"><span class="pre">∃ᶠ</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">F,</span> <span class="pre">P</span> <span class="pre">x</span></code> means <code class="docutils literal notranslate"><span class="pre">{x</span> <span class="pre">|</span> <span class="pre">¬P</span> <span class="pre">x}</span> <span class="pre">∉</span> <span class="pre">F</span></code>. For example, <code class="docutils literal notranslate"><span class="pre">∃ᶠ</span> <span class="pre">n</span> <span class="pre">in</span> <span class="pre">at_top,</span> <span class="pre">P</span> <span class="pre">n</span></code> means there are arbitrarily large <code class="docutils literal notranslate"><span class="pre">n</span></code> such that <code class="docutils literal notranslate"><span class="pre">P</span> <span class="pre">n</span></code> holds. The <code class="docutils literal notranslate"><span class="pre">∃ᶠ</span></code> notation stands for <code class="docutils literal notranslate"><span class="pre">Filter.frequently</span></code>.</p> <p>For a more sophisticated example, consider the following statement about a sequence <code class="docutils literal notranslate"><span class="pre">u</span></code>, a set <code class="docutils literal notranslate"><span class="pre">M</span></code>, and a value <code class="docutils literal notranslate"><span class="pre">x</span></code>:</p> <blockquote> <div><p>If <code class="docutils literal notranslate"><span class="pre">u</span></code> converges to <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">u</span> <span class="pre">n</span></code> belongs to <code class="docutils literal notranslate"><span class="pre">M</span></code> for sufficiently large <code class="docutils literal notranslate"><span class="pre">n</span></code> then <code class="docutils literal notranslate"><span class="pre">x</span></code> is in the closure of <code class="docutils literal notranslate"><span class="pre">M</span></code>.</p> </div></blockquote> <p>This can be formalized as follows:</p> <blockquote> <div><p><code class="docutils literal notranslate"><span class="pre">Tendsto</span> <span class="pre">u</span> <span class="pre">at_top</span> <span class="pre">(𝓝</span> <span class="pre">x)</span> <span class="pre">→</span> <span class="pre">(∀ᶠ</span> <span class="pre">n</span> <span class="pre">in</span> <span class="pre">at_top,</span> <span class="pre">u</span> <span class="pre">n</span> <span class="pre">∈</span> <span class="pre">M)</span> <span class="pre">→</span> <span class="pre">x</span> <span class="pre">∈</span> <span class="pre">closure</span> <span class="pre">M</span></code>.</p> </div></blockquote> <p>This is a special case of the theorem <code class="docutils literal notranslate"><span class="pre">mem_closure_of_tendsto</span></code> from the topology library. See if you can prove it using the quoted lemmas, using the fact that <code class="docutils literal notranslate"><span class="pre">cluster_pt</span> <span class="pre">x</span> <span class="pre">F</span></code> means <code class="docutils literal notranslate"><span class="pre">(𝓝</span> <span class="pre">x</span> <span class="pre">⊓</span> <span class="pre">F).ne_bot</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="k">#check</span> <span class="n">mem_closure_iff_clusterPt</span> <span class="k">#check</span> <span class="n">le_principal_iff</span> <span class="k">#check</span> <span class="n">neBot_of_le</span> <span class="kd">example</span> <span class="o">(</span><span class="n">u</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">M</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">hux</span> <span class="o">:</span> <span class="n">Tendsto</span> <span class="n">u</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">x</span><span class="o">))</span> <span class="o">(</span><span class="n">huM</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">n</span> <span class="k">in</span> <span class="n">atTop</span><span class="o">,</span> <span class="n">u</span> <span class="n">n</span> <span class="bp">∈</span> <span class="n">M</span><span class="o">)</span> <span class="o">:</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">closure</span> <span class="n">M</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> </section> <section id="metric-spaces"> <span id="index-2"></span><span id="id3"></span><h2><span class="section-number">8.2. </span>Metric spaces<a class="headerlink" href="#metric-spaces" title="Permalink to this heading"></a></h2> <p>Examples in the previous section focus on sequences of real numbers. In this section we will go up a bit in generality and focus on metric spaces. A metric space is a type <code class="docutils literal notranslate"><span class="pre">X</span></code> equipped with a distance function <code class="docutils literal notranslate"><span class="pre">dist</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">ℝ</span></code> which is a generalization of the function <code class="docutils literal notranslate"><span class="pre">fun</span> <span class="pre">x</span> <span class="pre">y</span> <span class="pre">↦</span> <span class="pre">|x</span> <span class="pre">-</span> <span class="pre">y|</span></code> from the case where <code class="docutils literal notranslate"><span class="pre">X</span> <span class="pre">=</span> <span class="pre">ℝ</span></code>.</p> <p>Introducing such a space is easy and we will check all properties required from the distance function.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">X</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">(</span><span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">X</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">dist</span> <span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">dist_nonneg</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">dist</span> <span class="n">a</span> <span class="n">b</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">dist_eq_zero</span> <span class="o">:</span> <span class="n">dist</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">=</span> <span class="mi">0</span> <span class="bp">↔</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">b</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">dist_comm</span> <span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">dist</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">=</span> <span class="n">dist</span> <span class="n">b</span> <span class="n">a</span><span class="o">)</span> <span class="k">#check</span> <span class="o">(</span><span class="n">dist_triangle</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="o">:</span> <span class="n">dist</span> <span class="n">a</span> <span class="n">c</span> <span class="bp">≤</span> <span class="n">dist</span> <span class="n">a</span> <span class="n">b</span> <span class="bp">+</span> <span class="n">dist</span> <span class="n">b</span> <span class="n">c</span><span class="o">)</span> </pre></div> </div> <p>Note we also have variants where the distance can be infinite or where <code class="docutils literal notranslate"><span class="pre">dist</span> <span class="pre">a</span> <span class="pre">b</span></code> can be zero without having <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">=</span> <span class="pre">b</span></code> or both. They are called <code class="docutils literal notranslate"><span class="pre">EMetricSpace</span></code>, <code class="docutils literal notranslate"><span class="pre">PseudoMetricSpace</span></code> and <code class="docutils literal notranslate"><span class="pre">PseudoEMetricSpace</span></code> respectively (here “e” stands for “extended”).</p> <p>Note that our journey from <code class="docutils literal notranslate"><span class="pre">ℝ</span></code> to metric spaces jumped over the special case of normed spaces that also require linear algebra and will be explained as part of the calculus chapter.</p> <section id="convergence-and-continuity"> <h3><span class="section-number">8.2.1. </span>Convergence and continuity<a class="headerlink" href="#convergence-and-continuity" title="Permalink to this heading"></a></h3> <p>Using distance functions, we can already define convergent sequences and continuous functions between metric spaces. They are actually defined in a more general setting covered in the next section, but we have lemmas recasting the definition is terms of distances.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">u</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">X</span><span class="o">}</span> <span class="o">{</span><span class="n">a</span> <span class="o">:</span> <span class="n">X</span><span class="o">}</span> <span class="o">:</span> <span class="n">Tendsto</span> <span class="n">u</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">a</span><span class="o">)</span> <span class="bp">↔</span> <span class="bp">∀</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">N</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">n</span> <span class="bp">≥</span> <span class="n">N</span><span class="o">,</span> <span class="n">dist</span> <span class="o">(</span><span class="n">u</span> <span class="n">n</span><span class="o">)</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">ε</span> <span class="o">:=</span> <span class="n">Metric.tendsto_atTop</span> <span class="kd">example</span> <span class="o">{</span><span class="n">X</span> <span class="n">Y</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">Y</span><span class="o">]</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">}</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="n">f</span> <span class="bp">↔</span> <span class="bp">∀</span> <span class="n">x</span> <span class="o">:</span> <span class="n">X</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">δ</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">x'</span><span class="o">,</span> <span class="n">dist</span> <span class="n">x'</span> <span class="n">x</span> <span class="bp"><</span> <span class="n">δ</span> <span class="bp">→</span> <span class="n">dist</span> <span class="o">(</span><span class="n">f</span> <span class="n">x'</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="bp"><</span> <span class="n">ε</span> <span class="o">:=</span> <span class="n">Metric.continuous_iff</span> </pre></div> </div> <p id="index-3">A <em>lot</em> of lemmas have some continuity assumptions, no we end up proving a lot of continuity results and there is a <code class="docutils literal notranslate"><span class="pre">continuity</span></code> tactic devoted to this task. Let’s prove a continuity statement that will be needed in an exercise below. Notice that Lean knows how to treat a product of two metric spaces as a metric space, so it makes sense to consider continuous functions from <code class="docutils literal notranslate"><span class="pre">X</span> <span class="pre">×</span> <span class="pre">X</span></code> to <code class="docutils literal notranslate"><span class="pre">ℝ</span></code>. In particular the (uncurried version of the) distance function is such a function.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">X</span> <span class="n">Y</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">Y</span><span class="o">]</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">}</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="k">fun</span> <span class="n">p</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">×</span> <span class="n">X</span> <span class="bp">=></span> <span class="n">dist</span> <span class="o">(</span><span class="n">f</span> <span class="n">p.1</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="n">p.2</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">continuity</span> </pre></div> </div> <p>This tactic is a bit slow, so it is also useful to know how to do it by hand. We first need to use that <code class="docutils literal notranslate"><span class="pre">fun</span> <span class="pre">p</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">×</span> <span class="pre">X</span> <span class="pre">↦</span> <span class="pre">f</span> <span class="pre">p.1</span></code> is continuous because it is the composition of <code class="docutils literal notranslate"><span class="pre">f</span></code>, which is continuous by assumption <code class="docutils literal notranslate"><span class="pre">hf</span></code>, and the projection <code class="docutils literal notranslate"><span class="pre">prod.fst</span></code> whose continuity is the content of the lemma <code class="docutils literal notranslate"><span class="pre">continuous_fst</span></code>. The composition property is <code class="docutils literal notranslate"><span class="pre">Continuous.comp</span></code> which is in the <code class="docutils literal notranslate"><span class="pre">Continuous</span></code> namespace so we can use dot notation to compress <code class="docutils literal notranslate"><span class="pre">Continuous.comp</span> <span class="pre">hf</span> <span class="pre">continuous_fst</span></code> into <code class="docutils literal notranslate"><span class="pre">hf.comp</span> <span class="pre">continuous_fst</span></code> which is actually more readable since it really reads as composing our assumption and our lemma. We can do the same for the second component to get continuity of <code class="docutils literal notranslate"><span class="pre">fun</span> <span class="pre">p</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">×</span> <span class="pre">X</span> <span class="pre">↦</span> <span class="pre">f</span> <span class="pre">p.2</span></code>. We then assemble those two continuities using <code class="docutils literal notranslate"><span class="pre">Continuous.prod_mk</span></code> to get <code class="docutils literal notranslate"><span class="pre">(hf.comp</span> <span class="pre">continuous_fst).prod_mk</span> <span class="pre">(hf.comp</span> <span class="pre">continuous_snd)</span> <span class="pre">:</span> <span class="pre">Continuous</span> <span class="pre">(fun</span> <span class="pre">p</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">×</span> <span class="pre">X</span> <span class="pre">↦</span> <span class="pre">(f</span> <span class="pre">p.1,</span> <span class="pre">f</span> <span class="pre">p.2))</span></code> and compose once more to get our full proof.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">X</span> <span class="n">Y</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">Y</span><span class="o">]</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">}</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="k">fun</span> <span class="n">p</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">×</span> <span class="n">X</span> <span class="bp">=></span> <span class="n">dist</span> <span class="o">(</span><span class="n">f</span> <span class="n">p.1</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="n">p.2</span><span class="o">)</span> <span class="o">:=</span> <span class="n">continuous_dist.comp</span> <span class="o">((</span><span class="n">hf.comp</span> <span class="n">continuous_fst</span><span class="o">)</span><span class="bp">.</span><span class="n">prod_mk</span> <span class="o">(</span><span class="n">hf.comp</span> <span class="n">continuous_snd</span><span class="o">))</span> </pre></div> </div> <p>The combination of <code class="docutils literal notranslate"><span class="pre">Continuous.prod_mk</span></code> and <code class="docutils literal notranslate"><span class="pre">continuous_dist</span></code> via <code class="docutils literal notranslate"><span class="pre">Continuous.comp</span></code> feels clunky, even when heavily using dot notation as above. A more serious issue is that this nice proof requires a lot of planning. Lean accepts the above proof term because it is a full term proving a statement which is definitionally equivalent to our goal, the crucial definition to unfold being that of a composition of functions. Indeed our target function <code class="docutils literal notranslate"><span class="pre">fun</span> <span class="pre">p</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">×</span> <span class="pre">X</span> <span class="pre">↦</span> <span class="pre">dist</span> <span class="pre">(f</span> <span class="pre">p.1)</span> <span class="pre">(f</span> <span class="pre">p.2)</span></code> is not presented as a composition. The proof term we provided proves continuity of <code class="docutils literal notranslate"><span class="pre">dist</span> <span class="pre">∘</span> <span class="pre">(fun</span> <span class="pre">p</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">×</span> <span class="pre">X</span> <span class="pre">↦</span> <span class="pre">(f</span> <span class="pre">p.1,</span> <span class="pre">f</span> <span class="pre">p.2))</span></code> which happens to be definitionally equal to our target function. But if we try to build this proof gradually using tactics starting with <code class="docutils literal notranslate"><span class="pre">apply</span> <span class="pre">continuous_dist.comp</span></code> then Lean’s elaborator will fail to recognize a composition and refuse to apply this lemma. It is especially bad at this when products of types are involved.</p> <p>A better lemma to apply here is <code class="docutils literal notranslate"><span class="pre">Continuous.dist</span> <span class="pre">{f</span> <span class="pre">g</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">Y}</span> <span class="pre">:</span> <span class="pre">Continuous</span> <span class="pre">f</span> <span class="pre">→</span> <span class="pre">Continuous</span> <span class="pre">g</span> <span class="pre">→</span> <span class="pre">Continuous</span> <span class="pre">(fun</span> <span class="pre">x</span> <span class="pre">↦</span> <span class="pre">dist</span> <span class="pre">(f</span> <span class="pre">x)</span> <span class="pre">(g</span> <span class="pre">x))</span></code> which is nicer to Lean’s elaborator and also provides a shorter proof when directly providing a full proof term, as can be seen from the following two new proofs of the above statement:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">X</span> <span class="n">Y</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">Y</span><span class="o">]</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">}</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="k">fun</span> <span class="n">p</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">×</span> <span class="n">X</span> <span class="bp">=></span> <span class="n">dist</span> <span class="o">(</span><span class="n">f</span> <span class="n">p.1</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="n">p.2</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">apply</span> <span class="n">Continuous.dist</span> <span class="n">exact</span> <span class="n">hf.comp</span> <span class="n">continuous_fst</span> <span class="n">exact</span> <span class="n">hf.comp</span> <span class="n">continuous_snd</span> <span class="kd">example</span> <span class="o">{</span><span class="n">X</span> <span class="n">Y</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">Y</span><span class="o">]</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">}</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="k">fun</span> <span class="n">p</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">×</span> <span class="n">X</span> <span class="bp">=></span> <span class="n">dist</span> <span class="o">(</span><span class="n">f</span> <span class="n">p.1</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="n">p.2</span><span class="o">)</span> <span class="o">:=</span> <span class="o">(</span><span class="n">hf.comp</span> <span class="n">continuous_fst</span><span class="o">)</span><span class="bp">.</span><span class="n">dist</span> <span class="o">(</span><span class="n">hf.comp</span> <span class="n">continuous_snd</span><span class="o">)</span> </pre></div> </div> <p>Note that, without the elaboration issue coming from composition, another way to compress our proof would be to use <code class="docutils literal notranslate"><span class="pre">Continuous.prod_map</span></code> which is sometimes useful and gives as an alternate proof term <code class="docutils literal notranslate"><span class="pre">continuous_dist.comp</span> <span class="pre">(hf.prod_map</span> <span class="pre">hf)</span></code> which even shorter to type.</p> <p>Since it is sad to decide between a version which is better for elaboration and a version which is shorter to type, let us wrap this discussion with a last bit of compression offered by <code class="docutils literal notranslate"><span class="pre">Continuous.fst'</span></code> which allows to compress <code class="docutils literal notranslate"><span class="pre">hf.comp</span> <span class="pre">continuous_fst</span></code> to <code class="docutils literal notranslate"><span class="pre">hf.fst'</span></code> (and the same with <code class="docutils literal notranslate"><span class="pre">snd</span></code>) and get our final proof, now bordering obfuscation.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">X</span> <span class="n">Y</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">Y</span><span class="o">]</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">}</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="k">fun</span> <span class="n">p</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">×</span> <span class="n">X</span> <span class="bp">=></span> <span class="n">dist</span> <span class="o">(</span><span class="n">f</span> <span class="n">p.1</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="n">p.2</span><span class="o">)</span> <span class="o">:=</span> <span class="n">hf.fst'.dist</span> <span class="n">hf.snd'</span> </pre></div> </div> <p>It’s your turn now to prove some continuity lemma. After trying the continuity tactic, you will need <code class="docutils literal notranslate"><span class="pre">Continuous.add</span></code>, <code class="docutils literal notranslate"><span class="pre">continuous_pow</span></code> and <code class="docutils literal notranslate"><span class="pre">continuous_id</span></code> to do it by hand.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="k">fun</span> <span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">=></span> <span class="n">f</span> <span class="o">(</span><span class="n">x</span> <span class="bp">^</span> <span class="mi">2</span> <span class="bp">+</span> <span class="n">x</span><span class="o">)</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>So far we saw continuity as a global notion, but one can also define continuity at a point.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">X</span> <span class="n">Y</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">Y</span><span class="o">]</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">X</span><span class="o">)</span> <span class="o">:</span> <span class="n">ContinuousAt</span> <span class="n">f</span> <span class="n">a</span> <span class="bp">↔</span> <span class="bp">∀</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">δ</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="bp">∀</span> <span class="o">{</span><span class="n">x</span><span class="o">},</span> <span class="n">dist</span> <span class="n">x</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">δ</span> <span class="bp">→</span> <span class="n">dist</span> <span class="o">(</span><span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="n">a</span><span class="o">)</span> <span class="bp"><</span> <span class="n">ε</span> <span class="o">:=</span> <span class="n">Metric.continuousAt_iff</span> </pre></div> </div> </section> <section id="balls-open-sets-and-closed-sets"> <h3><span class="section-number">8.2.2. </span>Balls, open sets and closed sets<a class="headerlink" href="#balls-open-sets-and-closed-sets" title="Permalink to this heading"></a></h3> <p>Once we have a distance function, the most important geometric definitions are (open) balls and closed balls.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">(</span><span class="n">r</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">Metric.ball</span> <span class="n">a</span> <span class="n">r</span> <span class="bp">=</span> <span class="o">{</span> <span class="n">b</span> <span class="bp">|</span> <span class="n">dist</span> <span class="n">b</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">r</span> <span class="o">}</span> <span class="o">:=</span> <span class="n">rfl</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">Metric.closedBall</span> <span class="n">a</span> <span class="n">r</span> <span class="bp">=</span> <span class="o">{</span> <span class="n">b</span> <span class="bp">|</span> <span class="n">dist</span> <span class="n">b</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">r</span> <span class="o">}</span> <span class="o">:=</span> <span class="n">rfl</span> </pre></div> </div> <p>Note that <cite>r</cite> is any real number here, there is no sign restriction. Of course some statements do require a radius condition.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">hr</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">r</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">∈</span> <span class="n">Metric.ball</span> <span class="n">a</span> <span class="n">r</span> <span class="o">:=</span> <span class="n">Metric.mem_ball_self</span> <span class="n">hr</span> <span class="kd">example</span> <span class="o">(</span><span class="n">hr</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">r</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">∈</span> <span class="n">Metric.closedBall</span> <span class="n">a</span> <span class="n">r</span> <span class="o">:=</span> <span class="n">Metric.mem_closedBall_self</span> <span class="n">hr</span> </pre></div> </div> <p>Once we have balls, we can define open sets. They are actually defined in a more general setting covered in the next section, but we have lemmas recasting the definition is terms of balls.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">)</span> <span class="o">:</span> <span class="n">IsOpen</span> <span class="n">s</span> <span class="bp">↔</span> <span class="bp">∀</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="n">Metric.ball</span> <span class="n">x</span> <span class="n">ε</span> <span class="bp">⊆</span> <span class="n">s</span> <span class="o">:=</span> <span class="n">Metric.isOpen_iff</span> </pre></div> </div> <p>Then closed sets are sets whose complement is open. Their important property is they are closed under limits. The closure of a set is the smallest subset containing it.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">:</span> <span class="n">IsClosed</span> <span class="n">s</span> <span class="bp">↔</span> <span class="n">IsOpen</span> <span class="o">(</span><span class="n">s</span><span class="bp">ᶜ</span><span class="o">)</span> <span class="o">:=</span> <span class="n">isOpen_compl_iff.symm</span> <span class="kd">example</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hs</span> <span class="o">:</span> <span class="n">IsClosed</span> <span class="n">s</span><span class="o">)</span> <span class="o">{</span><span class="n">u</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hu</span> <span class="o">:</span> <span class="n">Tendsto</span> <span class="n">u</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">a</span><span class="o">))</span> <span class="o">(</span><span class="n">hus</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="n">u</span> <span class="n">n</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">∈</span> <span class="n">s</span> <span class="o">:=</span> <span class="n">hs.mem_of_tendsto</span> <span class="n">hu</span> <span class="o">(</span><span class="n">eventually_of_forall</span> <span class="n">hus</span><span class="o">)</span> <span class="kd">example</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">∈</span> <span class="n">closure</span> <span class="n">s</span> <span class="bp">↔</span> <span class="bp">∀</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">b</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="n">a</span> <span class="bp">∈</span> <span class="n">Metric.ball</span> <span class="n">b</span> <span class="n">ε</span> <span class="o">:=</span> <span class="n">Metric.mem_closure_iff</span> </pre></div> </div> <p>Do the next exercise without using <cite>mem_closure_iff_seq_limit</cite></p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">u</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hu</span> <span class="o">:</span> <span class="n">Tendsto</span> <span class="n">u</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">a</span><span class="o">))</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hs</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="n">u</span> <span class="n">n</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">)</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">∈</span> <span class="n">closure</span> <span class="n">s</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>Remember from the filters sections that neighborhood filters play a big role in mathlib. In the metric space context, the crucial point is that balls provide bases for those filters. The main lemmas here are <code class="docutils literal notranslate"><span class="pre">Metric.nhds_basis_ball</span></code> and <code class="docutils literal notranslate"><span class="pre">Metric.nhds_basis_closedBall</span></code> that claim this for open and closed balls with positive radius. The center point is an implicit argument so we can invoke <code class="docutils literal notranslate"><span class="pre">Filter.HasBasis.mem_iff</span></code> as in the following example.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">X</span><span class="o">}</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∈</span> <span class="bp">𝓝</span> <span class="n">x</span> <span class="bp">↔</span> <span class="bp">∃</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="n">Metric.ball</span> <span class="n">x</span> <span class="n">ε</span> <span class="bp">⊆</span> <span class="n">s</span> <span class="o">:=</span> <span class="n">Metric.nhds_basis_ball.mem_iff</span> <span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">X</span><span class="o">}</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∈</span> <span class="bp">𝓝</span> <span class="n">x</span> <span class="bp">↔</span> <span class="bp">∃</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="n">Metric.closedBall</span> <span class="n">x</span> <span class="n">ε</span> <span class="bp">⊆</span> <span class="n">s</span> <span class="o">:=</span> <span class="n">Metric.nhds_basis_closedBall.mem_iff</span> </pre></div> </div> </section> <section id="compactness"> <h3><span class="section-number">8.2.3. </span>Compactness<a class="headerlink" href="#compactness" title="Permalink to this heading"></a></h3> <p>Compactness is an important topological notion. It distinguishes subsets of a metric space that enjoy the same kind of properties as segments in reals compared to other intervals:</p> <ul class="simple"> <li><p>Any sequence taking value in a compact set has a subsequence that converges in this set</p></li> <li><p>Any continuous function on a nonempty compact set with values in real numbers is bounded and achieves its bounds somewhere (this is called the extreme values theorem).</p></li> <li><p>Compact sets are closed sets.</p></li> </ul> <p>Let us first check that the unit interval in reals is indeed a compact set, and then check the above claims for compact sets in general metric spaces. In the second statement we only need continuity on the given set so we will use <code class="docutils literal notranslate"><span class="pre">ContinuousOn</span></code> instead of <code class="docutils literal notranslate"><span class="pre">Continuous</span></code>, and we will give separate statements for the minimum and the maximum. Of course all these results are deduced from more general versions, some of which will be discussed in later sections.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">IsCompact</span> <span class="o">(</span><span class="n">Set.Icc</span> <span class="mi">0</span> <span class="mi">1</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:=</span> <span class="n">isCompact_Icc</span> <span class="kd">example</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hs</span> <span class="o">:</span> <span class="n">IsCompact</span> <span class="n">s</span><span class="o">)</span> <span class="o">{</span><span class="n">u</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hu</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="n">u</span> <span class="n">n</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">a</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">φ</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℕ</span><span class="o">,</span> <span class="n">StrictMono</span> <span class="n">φ</span> <span class="bp">∧</span> <span class="n">Tendsto</span> <span class="o">(</span><span class="n">u</span> <span class="bp">∘</span> <span class="n">φ</span><span class="o">)</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">a</span><span class="o">)</span> <span class="o">:=</span> <span class="n">hs.tendsto_subseq</span> <span class="n">hu</span> <span class="kd">example</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hs</span> <span class="o">:</span> <span class="n">IsCompact</span> <span class="n">s</span><span class="o">)</span> <span class="o">(</span><span class="n">hs'</span> <span class="o">:</span> <span class="n">s.Nonempty</span><span class="o">)</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">hfs</span> <span class="o">:</span> <span class="n">ContinuousOn</span> <span class="n">f</span> <span class="n">s</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">y</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">≤</span> <span class="n">f</span> <span class="n">y</span> <span class="o">:=</span> <span class="n">hs.exists_forall_le</span> <span class="n">hs'</span> <span class="n">hfs</span> <span class="kd">example</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hs</span> <span class="o">:</span> <span class="n">IsCompact</span> <span class="n">s</span><span class="o">)</span> <span class="o">(</span><span class="n">hs'</span> <span class="o">:</span> <span class="n">s.Nonempty</span><span class="o">)</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">hfs</span> <span class="o">:</span> <span class="n">ContinuousOn</span> <span class="n">f</span> <span class="n">s</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">y</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="n">f</span> <span class="n">y</span> <span class="bp">≤</span> <span class="n">f</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">hs.exists_forall_ge</span> <span class="n">hs'</span> <span class="n">hfs</span> <span class="kd">example</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hs</span> <span class="o">:</span> <span class="n">IsCompact</span> <span class="n">s</span><span class="o">)</span> <span class="o">:</span> <span class="n">IsClosed</span> <span class="n">s</span> <span class="o">:=</span> <span class="n">hs.isClosed</span> </pre></div> </div> <p>We can also metric spaces which are globally compact, using an extra <code class="docutils literal notranslate"><span class="pre">Prop</span></code>-valued type class:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">X</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">[</span><span class="n">CompactSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">:</span> <span class="n">IsCompact</span> <span class="o">(</span><span class="n">univ</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">)</span> <span class="o">:=</span> <span class="n">isCompact_univ</span> </pre></div> </div> <p>In a compact metric space any closed set is compact, this is <code class="docutils literal notranslate"><span class="pre">IsCompact.isClosed</span></code>.</p> </section> <section id="uniformly-continuous-functions"> <h3><span class="section-number">8.2.4. </span>Uniformly continuous functions<a class="headerlink" href="#uniformly-continuous-functions" title="Permalink to this heading"></a></h3> <p>We now turn to uniformity notions on metric spaces : uniformly continuous functions, Cauchy sequences and completeness. Again those are defined in a more general context but we have lemmas in the metric name space to access their elementary definitions. We start with uniform continuity.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">X</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">{</span><span class="n">Y</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">Y</span><span class="o">]</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">}</span> <span class="o">:</span> <span class="n">UniformContinuous</span> <span class="n">f</span> <span class="bp">↔</span> <span class="bp">∀</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">δ</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="bp">∀</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">X</span><span class="o">},</span> <span class="n">dist</span> <span class="n">a</span> <span class="n">b</span> <span class="bp"><</span> <span class="n">δ</span> <span class="bp">→</span> <span class="n">dist</span> <span class="o">(</span><span class="n">f</span> <span class="n">a</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="n">b</span><span class="o">)</span> <span class="bp"><</span> <span class="n">ε</span> <span class="o">:=</span> <span class="n">Metric.uniformContinuous_iff</span> </pre></div> </div> <p>In order to practice manipulating all those definitions, we will prove that continuous functions from a compact metric space to a metric space are uniformly continuous (we will see a more general version in a later section).</p> <p>We will first give an informal sketch. Let <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">Y</span></code> be a continuous function from a compact metric space to a metric space. We fix <code class="docutils literal notranslate"><span class="pre">ε</span> <span class="pre">></span> <span class="pre">0</span></code> and start looking for some <code class="docutils literal notranslate"><span class="pre">δ</span></code>.</p> <p>Let <code class="docutils literal notranslate"><span class="pre">φ</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">×</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">ℝ</span> <span class="pre">:=</span> <span class="pre">fun</span> <span class="pre">p</span> <span class="pre">↦</span> <span class="pre">dist</span> <span class="pre">(f</span> <span class="pre">p.1)</span> <span class="pre">(f</span> <span class="pre">p.2)</span></code> and let <code class="docutils literal notranslate"><span class="pre">K</span> <span class="pre">:=</span> <span class="pre">{</span> <span class="pre">p</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">×</span> <span class="pre">X</span> <span class="pre">|</span> <span class="pre">ε</span> <span class="pre">≤</span> <span class="pre">φ</span> <span class="pre">p</span> <span class="pre">}</span></code>. Observe <code class="docutils literal notranslate"><span class="pre">φ</span></code> is continuous since <code class="docutils literal notranslate"><span class="pre">f</span></code> and distance are continuous. And <code class="docutils literal notranslate"><span class="pre">K</span></code> is clearly closed (use <code class="docutils literal notranslate"><span class="pre">isClosed_le</span></code>) hence compact since <code class="docutils literal notranslate"><span class="pre">X</span></code> is compact.</p> <p>Then we discuss two possibilities using <code class="docutils literal notranslate"><span class="pre">eq_empty_or_nonempty</span></code>. If <code class="docutils literal notranslate"><span class="pre">K</span></code> is empty then we are clearly done (we can set <code class="docutils literal notranslate"><span class="pre">δ</span> <span class="pre">=</span> <span class="pre">1</span></code> for instance). So let’s assume <code class="docutils literal notranslate"><span class="pre">K</span></code> is not empty, and use the extreme value theorem to choose <code class="docutils literal notranslate"><span class="pre">(x₀,</span> <span class="pre">x₁)</span></code> attaining the infimum of the distance function on <code class="docutils literal notranslate"><span class="pre">K</span></code>. We can then set <code class="docutils literal notranslate"><span class="pre">δ</span> <span class="pre">=</span> <span class="pre">dist</span> <span class="pre">x₀</span> <span class="pre">x₁</span></code> and check everything works.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">X</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">[</span><span class="n">CompactSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">{</span><span class="n">Y</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">MetricSpace</span> <span class="n">Y</span><span class="o">]</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">}</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">UniformContinuous</span> <span class="n">f</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> </section> <section id="completeness"> <h3><span class="section-number">8.2.5. </span>Completeness<a class="headerlink" href="#completeness" title="Permalink to this heading"></a></h3> <p>A Cauchy sequence in a metric space is a sequence whose terms get closer and closer to each other. There are a couple of equivalent ways to state that idea. In particular converging sequences are Cauchy. The converse is true only in so-called <em>complete</em> spaces.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">u</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">X</span><span class="o">)</span> <span class="o">:</span> <span class="n">CauchySeq</span> <span class="n">u</span> <span class="bp">↔</span> <span class="bp">∀</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">N</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">m</span> <span class="bp">≥</span> <span class="n">N</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">n</span> <span class="bp">≥</span> <span class="n">N</span><span class="o">,</span> <span class="n">dist</span> <span class="o">(</span><span class="n">u</span> <span class="n">m</span><span class="o">)</span> <span class="o">(</span><span class="n">u</span> <span class="n">n</span><span class="o">)</span> <span class="bp"><</span> <span class="n">ε</span> <span class="o">:=</span> <span class="n">Metric.cauchySeq_iff</span> <span class="kd">example</span> <span class="o">(</span><span class="n">u</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">X</span><span class="o">)</span> <span class="o">:</span> <span class="n">CauchySeq</span> <span class="n">u</span> <span class="bp">↔</span> <span class="bp">∀</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">N</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">n</span> <span class="bp">≥</span> <span class="n">N</span><span class="o">,</span> <span class="n">dist</span> <span class="o">(</span><span class="n">u</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">u</span> <span class="n">N</span><span class="o">)</span> <span class="bp"><</span> <span class="n">ε</span> <span class="o">:=</span> <span class="n">Metric.cauchySeq_iff'</span> <span class="kd">example</span> <span class="o">[</span><span class="n">CompleteSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">(</span><span class="n">u</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">X</span><span class="o">)</span> <span class="o">(</span><span class="n">hu</span> <span class="o">:</span> <span class="n">CauchySeq</span> <span class="n">u</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span><span class="o">,</span> <span class="n">Tendsto</span> <span class="n">u</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">x</span><span class="o">)</span> <span class="o">:=</span> <span class="n">cauchySeq_tendsto_of_complete</span> <span class="n">hu</span> </pre></div> </div> <p>We’ll practice using this definition by proving a convenient criterion which is a special case of a criterion appearing in mathlib. This is also a good opportunity to practice using big sums in a geometric context. In addition to the explanations from the filters section, you will probably need <code class="docutils literal notranslate"><span class="pre">tendsto_pow_atTop_nhds_0_of_lt_1</span></code>, <code class="docutils literal notranslate"><span class="pre">Tendsto.mul</span></code> and <code class="docutils literal notranslate"><span class="pre">dist_le_range_sum_dist</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">cauchySeq_of_le_geometric_two'</span> <span class="o">{</span><span class="n">u</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hu</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">,</span> <span class="n">dist</span> <span class="o">(</span><span class="n">u</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">u</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">))</span> <span class="bp">≤</span> <span class="o">(</span><span class="mi">1</span> <span class="bp">/</span> <span class="mi">2</span><span class="o">)</span> <span class="bp">^</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="n">CauchySeq</span> <span class="n">u</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">Metric.cauchySeq_iff'</span><span class="o">]</span> <span class="n">intro</span> <span class="n">ε</span> <span class="n">ε_pos</span> <span class="n">obtain</span> <span class="o">⟨</span><span class="n">N</span><span class="o">,</span> <span class="n">hN</span><span class="o">⟩</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">N</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">,</span> <span class="mi">1</span> <span class="bp">/</span> <span class="mi">2</span> <span class="bp">^</span> <span class="n">N</span> <span class="bp">*</span> <span class="mi">2</span> <span class="bp"><</span> <span class="n">ε</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="n">use</span> <span class="n">N</span> <span class="n">intro</span> <span class="n">n</span> <span class="n">hn</span> <span class="n">obtain</span> <span class="o">⟨</span><span class="n">k</span><span class="o">,</span> <span class="n">rfl</span> <span class="o">:</span> <span class="n">n</span> <span class="bp">=</span> <span class="n">N</span> <span class="bp">+</span> <span class="n">k</span><span class="o">⟩</span> <span class="o">:=</span> <span class="n">le_iff_exists_add.mp</span> <span class="n">hn</span> <span class="k">calc</span> <span class="n">dist</span> <span class="o">(</span><span class="n">u</span> <span class="o">(</span><span class="n">N</span> <span class="bp">+</span> <span class="n">k</span><span class="o">))</span> <span class="o">(</span><span class="n">u</span> <span class="n">N</span><span class="o">)</span> <span class="bp">=</span> <span class="n">dist</span> <span class="o">(</span><span class="n">u</span> <span class="o">(</span><span class="n">N</span> <span class="bp">+</span> <span class="mi">0</span><span class="o">))</span> <span class="o">(</span><span class="n">u</span> <span class="o">(</span><span class="n">N</span> <span class="bp">+</span> <span class="n">k</span><span class="o">))</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">_</span> <span class="bp">≤</span> <span class="bp">∑</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span> <span class="n">k</span><span class="o">,</span> <span class="n">dist</span> <span class="o">(</span><span class="n">u</span> <span class="o">(</span><span class="n">N</span> <span class="bp">+</span> <span class="n">i</span><span class="o">))</span> <span class="o">(</span><span class="n">u</span> <span class="o">(</span><span class="n">N</span> <span class="bp">+</span> <span class="o">(</span><span class="n">i</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)))</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">_</span> <span class="bp">≤</span> <span class="bp">∑</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span> <span class="n">k</span><span class="o">,</span> <span class="o">(</span><span class="mi">1</span> <span class="bp">/</span> <span class="mi">2</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="bp">^</span> <span class="o">(</span><span class="n">N</span> <span class="bp">+</span> <span class="n">i</span><span class="o">)</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">_</span> <span class="bp">=</span> <span class="mi">1</span> <span class="bp">/</span> <span class="mi">2</span> <span class="bp">^</span> <span class="n">N</span> <span class="bp">*</span> <span class="bp">∑</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span> <span class="n">k</span><span class="o">,</span> <span class="o">(</span><span class="mi">1</span> <span class="bp">/</span> <span class="mi">2</span><span class="o">)</span> <span class="bp">^</span> <span class="n">i</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">_</span> <span class="bp">≤</span> <span class="mi">1</span> <span class="bp">/</span> <span class="mi">2</span> <span class="bp">^</span> <span class="n">N</span> <span class="bp">*</span> <span class="mi">2</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">_</span> <span class="bp"><</span> <span class="n">ε</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>We are ready for the final boss of this section: Baire’s theorem for complete metric spaces! The proof skeleton below shows interesting techniques. It uses the <code class="docutils literal notranslate"><span class="pre">choose</span></code> tactic in its exclamation mark variant (you should experiment with removing this exclamation mark) and it shows how to define something inductively in the middle of a proof using <code class="docutils literal notranslate"><span class="pre">Nat.rec_on</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">open</span> <span class="n">Metric</span> <span class="kd">example</span> <span class="o">[</span><span class="n">CompleteSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">Set</span> <span class="n">X</span><span class="o">)</span> <span class="o">(</span><span class="n">ho</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="n">IsOpen</span> <span class="o">(</span><span class="n">f</span> <span class="n">n</span><span class="o">))</span> <span class="o">(</span><span class="n">hd</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="n">Dense</span> <span class="o">(</span><span class="n">f</span> <span class="n">n</span><span class="o">))</span> <span class="o">:</span> <span class="n">Dense</span> <span class="o">(</span><span class="bp">⋂</span> <span class="n">n</span><span class="o">,</span> <span class="n">f</span> <span class="n">n</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="k">let</span> <span class="n">B</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℝ</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">n</span> <span class="bp">=></span> <span class="o">(</span><span class="mi">1</span> <span class="bp">/</span> <span class="mi">2</span><span class="o">)</span> <span class="bp">^</span> <span class="n">n</span> <span class="k">have</span> <span class="n">Bpos</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">B</span> <span class="n">n</span> <span class="gr">sorry</span> <span class="c">/-</span><span class="cm"> Translate the density assumption into two functions `center` and `radius` associating</span> <span class="cm"> to any n, x, δ, δpos a center and a positive radius such that</span> <span class="cm"> `closedBall center radius` is included both in `f n` and in `closedBall x δ`.</span> <span class="cm"> We can also require `radius ≤ (1/2)^(n+1)`, to ensure we get a Cauchy sequence later. -/</span> <span class="k">have</span> <span class="o">:</span> <span class="bp">∀</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">X</span><span class="o">),</span> <span class="bp">∀</span> <span class="n">δ</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">y</span> <span class="o">:</span> <span class="n">X</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">r</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="n">r</span> <span class="bp">≤</span> <span class="n">B</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">)</span> <span class="bp">∧</span> <span class="n">closedBall</span> <span class="n">y</span> <span class="n">r</span> <span class="bp">⊆</span> <span class="n">closedBall</span> <span class="n">x</span> <span class="n">δ</span> <span class="bp">∩</span> <span class="n">f</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="n">choose</span><span class="bp">!</span> <span class="n">center</span> <span class="n">radius</span> <span class="n">Hpos</span> <span class="n">HB</span> <span class="n">Hball</span> <span class="n">using</span> <span class="n">this</span> <span class="n">intro</span> <span class="n">x</span> <span class="n">rw</span> <span class="o">[</span><span class="n">mem_closure_iff_nhds_basis</span> <span class="n">nhds_basis_closedBall</span><span class="o">]</span> <span class="n">intro</span> <span class="n">ε</span> <span class="n">εpos</span> <span class="c">/-</span><span class="cm"> `ε` is positive. We have to find a point in the ball of radius `ε` around `x`</span> <span class="cm"> belonging to all `f n`. For this, we construct inductively a sequence</span> <span class="cm"> `F n = (c n, r n)` such that the closed ball `closedBall (c n) (r n)` is included</span> <span class="cm"> in the previous ball and in `f n`, and such that `r n` is small enough to ensure</span> <span class="cm"> that `c n` is a Cauchy sequence. Then `c n` converges to a limit which belongs</span> <span class="cm"> to all the `f n`. -/</span> <span class="k">let</span> <span class="n">F</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">X</span> <span class="bp">×</span> <span class="n">ℝ</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">n</span> <span class="bp">=></span> <span class="n">Nat.recOn</span> <span class="n">n</span> <span class="o">(</span><span class="n">Prod.mk</span> <span class="n">x</span> <span class="o">(</span><span class="n">min</span> <span class="n">ε</span> <span class="o">(</span><span class="n">B</span> <span class="mi">0</span><span class="o">)))</span> <span class="k">fun</span> <span class="n">n</span> <span class="n">p</span> <span class="bp">=></span> <span class="n">Prod.mk</span> <span class="o">(</span><span class="n">center</span> <span class="n">n</span> <span class="n">p.1</span> <span class="n">p.2</span><span class="o">)</span> <span class="o">(</span><span class="n">radius</span> <span class="n">n</span> <span class="n">p.1</span> <span class="n">p.2</span><span class="o">)</span> <span class="k">let</span> <span class="n">c</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">X</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">n</span> <span class="bp">=></span> <span class="o">(</span><span class="n">F</span> <span class="n">n</span><span class="o">)</span><span class="bp">.</span><span class="mi">1</span> <span class="k">let</span> <span class="n">r</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℝ</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">n</span> <span class="bp">=></span> <span class="o">(</span><span class="n">F</span> <span class="n">n</span><span class="o">)</span><span class="bp">.</span><span class="mi">2</span> <span class="k">have</span> <span class="n">rpos</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">r</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="n">rB</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="n">r</span> <span class="n">n</span> <span class="bp">≤</span> <span class="n">B</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="n">incl</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="n">closedBall</span> <span class="o">(</span><span class="n">c</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">))</span> <span class="o">(</span><span class="n">r</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">))</span> <span class="bp">⊆</span> <span class="n">closedBall</span> <span class="o">(</span><span class="n">c</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">r</span> <span class="n">n</span><span class="o">)</span> <span class="bp">∩</span> <span class="n">f</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="n">cdist</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="n">dist</span> <span class="o">(</span><span class="n">c</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">c</span> <span class="o">(</span><span class="n">n</span> <span class="bp">+</span> <span class="mi">1</span><span class="o">))</span> <span class="bp">≤</span> <span class="n">B</span> <span class="n">n</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="o">:</span> <span class="n">CauchySeq</span> <span class="n">c</span> <span class="o">:=</span> <span class="n">cauchySeq_of_le_geometric_two'</span> <span class="n">cdist</span> <span class="c1">-- as the sequence `c n` is Cauchy in a complete space, it converges to a limit `y`.</span> <span class="n">rcases</span> <span class="n">cauchySeq_tendsto_of_complete</span> <span class="n">this</span> <span class="k">with</span> <span class="o">⟨</span><span class="n">y</span><span class="o">,</span> <span class="n">ylim</span><span class="o">⟩</span> <span class="c1">-- this point `y` will be the desired point. We will check that it belongs to all</span> <span class="c1">-- `f n` and to `ball x ε`.</span> <span class="n">use</span> <span class="n">y</span> <span class="k">have</span> <span class="n">I</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">m</span> <span class="bp">≥</span> <span class="n">n</span><span class="o">,</span> <span class="n">closedBall</span> <span class="o">(</span><span class="n">c</span> <span class="n">m</span><span class="o">)</span> <span class="o">(</span><span class="n">r</span> <span class="n">m</span><span class="o">)</span> <span class="bp">⊆</span> <span class="n">closedBall</span> <span class="o">(</span><span class="n">c</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">r</span> <span class="n">n</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="n">yball</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="n">y</span> <span class="bp">∈</span> <span class="n">closedBall</span> <span class="o">(</span><span class="n">c</span> <span class="n">n</span><span class="o">)</span> <span class="o">(</span><span class="n">r</span> <span class="n">n</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="gr">sorry</span> </pre></div> </div> </section> </section> <section id="topological-spaces"> <span id="index-4"></span><span id="id4"></span><h2><span class="section-number">8.3. </span>Topological spaces<a class="headerlink" href="#topological-spaces" title="Permalink to this heading"></a></h2> <section id="fundamentals"> <h3><span class="section-number">8.3.1. </span>Fundamentals<a class="headerlink" href="#fundamentals" title="Permalink to this heading"></a></h3> <p>We now go up in generality and introduce topological spaces. We will review the two main ways to define topological spaces and then explain how the category of topological spaces is much better behaved than the category of metric spaces. Note that we won’t be using mathlib category theory here, only having a somewhat categorical point of view.</p> <p>The first way to think about the transition from metric spaces to topological spaces is that we only remember the notion of open sets (or equivalently the notion of closed sets). From this point of view, a topological space is a type equipped with a collection of sets that are called open sets. This collection has to satisfy a number of axioms presented below (this collection is slightly redundant but we will ignore that).</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">section</span> <span class="kd">variable</span> <span class="o">{</span><span class="n">X</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">TopologicalSpace</span> <span class="n">X</span><span class="o">]</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">IsOpen</span> <span class="o">(</span><span class="n">univ</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">)</span> <span class="o">:=</span> <span class="n">isOpen_univ</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">IsOpen</span> <span class="o">(</span><span class="bp">∅</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">)</span> <span class="o">:=</span> <span class="n">isOpen_empty</span> <span class="kd">example</span> <span class="o">{</span><span class="n">ι</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">ι</span> <span class="bp">→</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hs</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">i</span><span class="o">,</span> <span class="n">IsOpen</span> <span class="bp"><|</span> <span class="n">s</span> <span class="n">i</span><span class="o">)</span> <span class="o">:</span> <span class="n">IsOpen</span> <span class="o">(</span><span class="bp">⋃</span> <span class="n">i</span><span class="o">,</span> <span class="n">s</span> <span class="n">i</span><span class="o">)</span> <span class="o">:=</span> <span class="n">isOpen_iUnion</span> <span class="n">hs</span> <span class="kd">example</span> <span class="o">{</span><span class="n">ι</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">Fintype</span> <span class="n">ι</span><span class="o">]</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">ι</span> <span class="bp">→</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hs</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">i</span><span class="o">,</span> <span class="n">IsOpen</span> <span class="bp"><|</span> <span class="n">s</span> <span class="n">i</span><span class="o">)</span> <span class="o">:</span> <span class="n">IsOpen</span> <span class="o">(</span><span class="bp">⋂</span> <span class="n">i</span><span class="o">,</span> <span class="n">s</span> <span class="n">i</span><span class="o">)</span> <span class="o">:=</span> <span class="n">isOpen_iInter</span> <span class="n">hs</span> </pre></div> </div> <p>Closed sets are then defined as sets whose complement is open. A function between topological spaces is (globally) continuous if all preimages of open sets are open.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">Y</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">TopologicalSpace</span> <span class="n">Y</span><span class="o">]</span> <span class="kd">example</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">}</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="n">f</span> <span class="bp">↔</span> <span class="bp">∀</span> <span class="n">s</span><span class="o">,</span> <span class="n">IsOpen</span> <span class="n">s</span> <span class="bp">→</span> <span class="n">IsOpen</span> <span class="o">(</span><span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">s</span><span class="o">)</span> <span class="o">:=</span> <span class="n">continuous_def</span> </pre></div> </div> <p>With this definition we already see that, compared to metric spaces, topological spaces only remember enough information to talk about continuous functions: two topological structures on a type are the same if and only if they have the same continuous functions (indeed the identity function will be continuous in both direction if and only if the two structures have the same open sets).</p> <p>However as soon as we move on to continuity at a point we see the limitations of the approach based on open sets. In mathlib it is much more frequent to think of topological spaces as types equipped with a neighborhood filter <code class="docutils literal notranslate"><span class="pre">𝓝</span> <span class="pre">x</span></code> attached to each point <code class="docutils literal notranslate"><span class="pre">x</span></code> (the corresponding function <code class="docutils literal notranslate"><span class="pre">X</span> <span class="pre">→</span> <span class="pre">Filter</span> <span class="pre">X</span></code> satisfies certain conditions explained further down). Remember from the filters section that these gadget play two related roles. First <code class="docutils literal notranslate"><span class="pre">𝓝</span> <span class="pre">x</span></code> is seen as the generalized set of points of <code class="docutils literal notranslate"><span class="pre">X</span></code> that are close to <code class="docutils literal notranslate"><span class="pre">x</span></code>. And then it is seen as giving a way to say, for any predicate <code class="docutils literal notranslate"><span class="pre">P</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">Prop</span></code>, that this predicates holds for points that are close enough to <code class="docutils literal notranslate"><span class="pre">x</span></code>. Let us state that <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">Y</span></code> is continuous at <code class="docutils literal notranslate"><span class="pre">x</span></code>. The purely filtery way is to say that the direct image under <code class="docutils literal notranslate"><span class="pre">f</span></code> of the generalized set of points that are close to <code class="docutils literal notranslate"><span class="pre">x</span></code> is contained in the generalized set of points that are close to <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span></code>. Recall this spelled either <code class="docutils literal notranslate"><span class="pre">map</span> <span class="pre">f</span> <span class="pre">(𝓝</span> <span class="pre">x)</span> <span class="pre">≤</span> <span class="pre">𝓝</span> <span class="pre">(f</span> <span class="pre">x)</span></code> or <code class="docutils literal notranslate"><span class="pre">Tendsto</span> <span class="pre">f</span> <span class="pre">(𝓝</span> <span class="pre">x)</span> <span class="pre">(𝓝</span> <span class="pre">(f</span> <span class="pre">x))</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">}</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">X</span><span class="o">}</span> <span class="o">:</span> <span class="n">ContinuousAt</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">↔</span> <span class="n">map</span> <span class="n">f</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">x</span><span class="o">)</span> <span class="bp">≤</span> <span class="bp">𝓝</span> <span class="o">(</span><span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="o">:=</span> <span class="n">Iff.rfl</span> </pre></div> </div> <p>One can also spell it using both neighborhoods seen as ordinary sets and a neighborhood filter seen as a generalized set: “for any neighborhood <code class="docutils literal notranslate"><span class="pre">U</span></code> of <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">x</span></code>, all points close to <code class="docutils literal notranslate"><span class="pre">x</span></code> are sent to <code class="docutils literal notranslate"><span class="pre">U</span></code>”. Note that the proof is again <code class="docutils literal notranslate"><span class="pre">iff.rfl</span></code>, this point of view is definitionally equivalent to the previous one.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">}</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">X</span><span class="o">}</span> <span class="o">:</span> <span class="n">ContinuousAt</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">↔</span> <span class="bp">∀</span> <span class="n">U</span> <span class="bp">∈</span> <span class="bp">𝓝</span> <span class="o">(</span><span class="n">f</span> <span class="n">x</span><span class="o">),</span> <span class="bp">∀ᶠ</span> <span class="n">x</span> <span class="k">in</span> <span class="bp">𝓝</span> <span class="n">x</span><span class="o">,</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">U</span> <span class="o">:=</span> <span class="n">Iff.rfl</span> </pre></div> </div> <p>We now explain how to go from one point of view to the other. In terms of open sets, we can simply define members of <code class="docutils literal notranslate"><span class="pre">𝓝</span> <span class="pre">x</span></code> as sets that contain an open set containing <code class="docutils literal notranslate"><span class="pre">x</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">X</span><span class="o">}</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">∈</span> <span class="bp">𝓝</span> <span class="n">x</span> <span class="bp">↔</span> <span class="bp">∃</span> <span class="n">t</span><span class="o">,</span> <span class="n">t</span> <span class="bp">⊆</span> <span class="n">s</span> <span class="bp">∧</span> <span class="n">IsOpen</span> <span class="n">t</span> <span class="bp">∧</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">t</span> <span class="o">:=</span> <span class="n">mem_nhds_iff</span> </pre></div> </div> <p>To go in the other direction we need to discuss the condition that <code class="docutils literal notranslate"><span class="pre">𝓝</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">Filter</span> <span class="pre">X</span></code> must satisfy in order to be the neighborhood function of a topology.</p> <p>The first constraint is that <code class="docutils literal notranslate"><span class="pre">𝓝</span> <span class="pre">x</span></code>, seen as a generalized set, contains the set <code class="docutils literal notranslate"><span class="pre">{x}</span></code> seen as the generalized set <code class="docutils literal notranslate"><span class="pre">pure</span> <span class="pre">x</span></code> (explaining this weird name would be too much of a digression, so we simply accept it for now). Another way to say it is that if a predicate holds for points close to <code class="docutils literal notranslate"><span class="pre">x</span></code> then it holds at <code class="docutils literal notranslate"><span class="pre">x</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">X</span><span class="o">)</span> <span class="o">:</span> <span class="n">pure</span> <span class="n">x</span> <span class="bp">≤</span> <span class="bp">𝓝</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">pure_le_nhds</span> <span class="n">x</span> <span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">X</span><span class="o">)</span> <span class="o">(</span><span class="n">P</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="kt">Prop</span><span class="o">)</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">y</span> <span class="k">in</span> <span class="bp">𝓝</span> <span class="n">x</span><span class="o">,</span> <span class="n">P</span> <span class="n">y</span><span class="o">)</span> <span class="o">:</span> <span class="n">P</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">pure_le_nhds</span> <span class="n">x</span> <span class="n">h</span> </pre></div> </div> <p>Then a more subtle requirement is that, for any predicate <code class="docutils literal notranslate"><span class="pre">P</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">Prop</span></code> and any <code class="docutils literal notranslate"><span class="pre">x</span></code>, if <code class="docutils literal notranslate"><span class="pre">P</span> <span class="pre">y</span></code> holds for <code class="docutils literal notranslate"><span class="pre">y</span></code> close to <code class="docutils literal notranslate"><span class="pre">x</span></code> then for <code class="docutils literal notranslate"><span class="pre">y</span></code> close to <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">z</span></code> close to <code class="docutils literal notranslate"><span class="pre">y</span></code>, <code class="docutils literal notranslate"><span class="pre">P</span> <span class="pre">z</span></code> holds. More precisely we have:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">P</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="kt">Prop</span><span class="o">}</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">y</span> <span class="k">in</span> <span class="bp">𝓝</span> <span class="n">x</span><span class="o">,</span> <span class="n">P</span> <span class="n">y</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">y</span> <span class="k">in</span> <span class="bp">𝓝</span> <span class="n">x</span><span class="o">,</span> <span class="bp">∀ᶠ</span> <span class="n">z</span> <span class="k">in</span> <span class="bp">𝓝</span> <span class="n">y</span><span class="o">,</span> <span class="n">P</span> <span class="n">z</span> <span class="o">:=</span> <span class="n">eventually_eventually_nhds.mpr</span> <span class="n">h</span> </pre></div> </div> <p>Those two results characterize the functions <code class="docutils literal notranslate"><span class="pre">X</span> <span class="pre">→</span> <span class="pre">Filter</span> <span class="pre">X</span></code> that are neighborhood functions for a topological space structure on <code class="docutils literal notranslate"><span class="pre">X</span></code>. There is a still a function <code class="docutils literal notranslate"><span class="pre">topological_space.mk_of_nhds</span> <span class="pre">:</span> <span class="pre">(X</span> <span class="pre">→</span> <span class="pre">Filter</span> <span class="pre">X)</span> <span class="pre">→</span> <span class="pre">topological_space</span> <span class="pre">X</span></code> but it will give back its input as a neighborhood function only if it satisfies the above two constraints. More precisely we have a lemma <code class="docutils literal notranslate"><span class="pre">topological_space.nhds_mk_of_nhds</span></code> saying that in a different way and our next exercise deduces this different way from how we stated it above.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">Filter</span> <span class="n">α</span><span class="o">)</span> <span class="o">(</span><span class="n">H₀</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span><span class="o">,</span> <span class="n">pure</span> <span class="n">a</span> <span class="bp">≤</span> <span class="n">n</span> <span class="n">a</span><span class="o">)</span> <span class="o">(</span><span class="n">H</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">α</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">p</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="kt">Prop</span><span class="o">,</span> <span class="o">(</span><span class="bp">∀ᶠ</span> <span class="n">x</span> <span class="k">in</span> <span class="n">n</span> <span class="n">a</span><span class="o">,</span> <span class="n">p</span> <span class="n">x</span><span class="o">)</span> <span class="bp">→</span> <span class="bp">∀ᶠ</span> <span class="n">y</span> <span class="k">in</span> <span class="n">n</span> <span class="n">a</span><span class="o">,</span> <span class="bp">∀ᶠ</span> <span class="n">x</span> <span class="k">in</span> <span class="n">n</span> <span class="n">y</span><span class="o">,</span> <span class="n">p</span> <span class="n">x</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">a</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">s</span> <span class="bp">∈</span> <span class="n">n</span> <span class="n">a</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">t</span> <span class="bp">∈</span> <span class="n">n</span> <span class="n">a</span><span class="o">,</span> <span class="n">t</span> <span class="bp">⊆</span> <span class="n">s</span> <span class="bp">∧</span> <span class="bp">∀</span> <span class="n">a'</span> <span class="bp">∈</span> <span class="n">t</span><span class="o">,</span> <span class="n">s</span> <span class="bp">∈</span> <span class="n">n</span> <span class="n">a'</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>Note that <code class="docutils literal notranslate"><span class="pre">topological_space.mk_of_nhds</span></code> is not so frequently used, but it still good to know in what precise sense the neighborhood filters is all there is in a topological space structure.</p> <p>The next thing to know in order to efficiently use topological spaces in mathlib is that we use a lot of formal properties of <code class="docutils literal notranslate"><span class="pre">topological_space</span> <span class="pre">:</span> <span class="pre">Type</span> <span class="pre">u</span> <span class="pre">→</span> <span class="pre">Type</span> <span class="pre">u</span></code>. From a purely mathematical point of view, those formal properties are a very clean way to explain how topological spaces solve issues that metric spaces have. From this point of view, the issues solved by topological spaces is that metric spaces enjoy very little fonctoriality, and have very bad categorical properties in general. This comes on top of the fact already discussed that metric spaces contain a lot of geometrical information that is not topologically relevant.</p> <p>Let us focus on fonctoriality first. A metric space structure can be induced on a subset or, equivalently, it can be pulled back by an injective map. But that’s pretty much everything. They cannot be pulled back by general map or pushed forward, even by surjective maps.</p> <p>In particular there is no sensible distance to put on a quotient of a metric space or on an uncountable products of metric spaces. Consider for instance the type <code class="docutils literal notranslate"><span class="pre">ℝ</span> <span class="pre">→</span> <span class="pre">ℝ</span></code>, seen as a product of copies of <code class="docutils literal notranslate"><span class="pre">ℝ</span></code> indexed by <code class="docutils literal notranslate"><span class="pre">ℝ</span></code>. We would like to say that pointwise convergence of sequences of functions is a respectable notion of convergence. But there is no distance on <code class="docutils literal notranslate"><span class="pre">ℝ</span> <span class="pre">→</span> <span class="pre">ℝ</span></code> that gives this notion of convergence. Relatedly, there is no distance ensuring that a map <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">(ℝ</span> <span class="pre">→</span> <span class="pre">ℝ)</span></code> is continuous if and only <code class="docutils literal notranslate"><span class="pre">fun</span> <span class="pre">x</span> <span class="pre">↦</span> <span class="pre">f</span> <span class="pre">x</span> <span class="pre">t</span></code> is continuous for every <code class="docutils literal notranslate"><span class="pre">t</span> <span class="pre">:</span> <span class="pre">ℝ</span></code>.</p> <p>We now review the data used to solve all those issues. First we can use any map <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">Y</span></code> to push or pull topologies from one side to the other. Those two operations form a Galois connection.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">X</span> <span class="n">Y</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="kd">example</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">)</span> <span class="o">:</span> <span class="n">TopologicalSpace</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">TopologicalSpace</span> <span class="n">Y</span> <span class="o">:=</span> <span class="n">TopologicalSpace.coinduced</span> <span class="n">f</span> <span class="kd">example</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">)</span> <span class="o">:</span> <span class="n">TopologicalSpace</span> <span class="n">Y</span> <span class="bp">→</span> <span class="n">TopologicalSpace</span> <span class="n">X</span> <span class="o">:=</span> <span class="n">TopologicalSpace.induced</span> <span class="n">f</span> <span class="kd">example</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">)</span> <span class="o">(</span><span class="n">T_X</span> <span class="o">:</span> <span class="n">TopologicalSpace</span> <span class="n">X</span><span class="o">)</span> <span class="o">(</span><span class="n">T_Y</span> <span class="o">:</span> <span class="n">TopologicalSpace</span> <span class="n">Y</span><span class="o">)</span> <span class="o">:</span> <span class="n">TopologicalSpace.coinduced</span> <span class="n">f</span> <span class="n">T_X</span> <span class="bp">≤</span> <span class="n">T_Y</span> <span class="bp">↔</span> <span class="n">T_X</span> <span class="bp">≤</span> <span class="n">TopologicalSpace.induced</span> <span class="n">f</span> <span class="n">T_Y</span> <span class="o">:=</span> <span class="n">coinduced_le_iff_le_induced</span> </pre></div> </div> <p>Those operations are compactible with composition of functions. As usual, pushing forward is covariant and pulling back is contravariant, see <code class="docutils literal notranslate"><span class="pre">coinduced_compose</span></code> and <code class="docutils literal notranslate"><span class="pre">induced_compose</span></code>. On paper we will use notations <span class="math notranslate nohighlight">\(f_*T\)</span> for <code class="docutils literal notranslate"><span class="pre">topological_space.coinduced</span> <span class="pre">f</span> <span class="pre">T</span></code> and <span class="math notranslate nohighlight">\(f^*T\)</span> for <code class="docutils literal notranslate"><span class="pre">topological_space.induced</span> <span class="pre">f</span> <span class="pre">T</span></code>.</p> <p>Then the next big piece is a complete lattice structure on <code class="docutils literal notranslate"><span class="pre">topological_structure</span> <span class="pre">X</span></code> for any given structure. If you think of topologies are being primarily the data of open sets then you expect the order relation on <code class="docutils literal notranslate"><span class="pre">topological_structure</span> <span class="pre">X</span></code> to come from <code class="docutils literal notranslate"><span class="pre">Set</span> <span class="pre">(Set</span> <span class="pre">X)</span></code>, ie you expect <code class="docutils literal notranslate"><span class="pre">t</span> <span class="pre">≤</span> <span class="pre">t'</span></code> if a set <code class="docutils literal notranslate"><span class="pre">u</span></code> is open for <code class="docutils literal notranslate"><span class="pre">t'</span></code> as soon as it is open for <code class="docutils literal notranslate"><span class="pre">t</span></code>. However we already know that mathlib focuses on neighborhoods more than open sets so, for any <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">:</span> <span class="pre">X</span></code> we want <code class="docutils literal notranslate"><span class="pre">fun</span> <span class="pre">T</span> <span class="pre">:</span> <span class="pre">topological_space</span> <span class="pre">X</span> <span class="pre">↦</span> <span class="pre">@nhds</span> <span class="pre">X</span> <span class="pre">T</span> <span class="pre">x</span></code> to be order preserving. And we know the order relation on <code class="docutils literal notranslate"><span class="pre">filter</span> <span class="pre">X</span></code> is designed to ensure an order preserving <code class="docutils literal notranslate"><span class="pre">principal</span> <span class="pre">:</span> <span class="pre">Set</span> <span class="pre">X</span> <span class="pre">→</span> <span class="pre">Filter</span> <span class="pre">X</span></code>, allowing to see filters as generalized sets. So the order relation we do use on <code class="docutils literal notranslate"><span class="pre">topological_structure</span> <span class="pre">X</span></code> is opposite to the one coming from <code class="docutils literal notranslate"><span class="pre">Set</span> <span class="pre">(Set</span> <span class="pre">X)</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">T</span> <span class="n">T'</span> <span class="o">:</span> <span class="n">TopologicalSpace</span> <span class="n">X</span><span class="o">}</span> <span class="o">:</span> <span class="n">T</span> <span class="bp">≤</span> <span class="n">T'</span> <span class="bp">↔</span> <span class="bp">∀</span> <span class="n">s</span><span class="o">,</span> <span class="n">T'.IsOpen</span> <span class="n">s</span> <span class="bp">→</span> <span class="n">T.IsOpen</span> <span class="n">s</span> <span class="o">:=</span> <span class="n">Iff.rfl</span> </pre></div> </div> <p>Now we can recover continuity by combining the push-foward (or pull-back) operation with the order relation.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">T_X</span> <span class="o">:</span> <span class="n">TopologicalSpace</span> <span class="n">X</span><span class="o">)</span> <span class="o">(</span><span class="n">T_Y</span> <span class="o">:</span> <span class="n">TopologicalSpace</span> <span class="n">Y</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">)</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="n">f</span> <span class="bp">↔</span> <span class="n">TopologicalSpace.coinduced</span> <span class="n">f</span> <span class="n">T_X</span> <span class="bp">≤</span> <span class="n">T_Y</span> <span class="o">:=</span> <span class="n">continuous_iff_coinduced_le</span> </pre></div> </div> <p>With this definition and the compatibility of push-forward and composition, we get for free the universal property that, for any topological space <span class="math notranslate nohighlight">\(Z\)</span>, a function <span class="math notranslate nohighlight">\(g : Y → Z\)</span> is continuous for the topology <span class="math notranslate nohighlight">\(f_*T_X\)</span> if and only if <span class="math notranslate nohighlight">\(g ∘ f\)</span> is continuous.</p> <div class="math notranslate nohighlight"> \[\begin{split}g \text{ continuous } &⇔ g_*(f_*T_X) ≤ T_Z \\ &⇔ (g ∘ f)_* T_X ≤ T_Z \\ &⇔ g ∘ f \text{ continuous}\end{split}\]</div> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">Z</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">)</span> <span class="o">(</span><span class="n">T_X</span> <span class="o">:</span> <span class="n">TopologicalSpace</span> <span class="n">X</span><span class="o">)</span> <span class="o">(</span><span class="n">T_Z</span> <span class="o">:</span> <span class="n">TopologicalSpace</span> <span class="n">Z</span><span class="o">)</span> <span class="o">(</span><span class="n">g</span> <span class="o">:</span> <span class="n">Y</span> <span class="bp">→</span> <span class="n">Z</span><span class="o">)</span> <span class="o">:</span> <span class="bp">@</span><span class="n">Continuous</span> <span class="n">Y</span> <span class="n">Z</span> <span class="o">(</span><span class="n">TopologicalSpace.coinduced</span> <span class="n">f</span> <span class="n">T_X</span><span class="o">)</span> <span class="n">T_Z</span> <span class="n">g</span> <span class="bp">↔</span> <span class="bp">@</span><span class="n">Continuous</span> <span class="n">X</span> <span class="n">Z</span> <span class="n">T_X</span> <span class="n">T_Z</span> <span class="o">(</span><span class="n">g</span> <span class="bp">∘</span> <span class="n">f</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">rw</span> <span class="o">[</span><span class="n">continuous_iff_coinduced_le</span><span class="o">,</span> <span class="n">coinduced_compose</span><span class="o">,</span> <span class="n">continuous_iff_coinduced_le</span><span class="o">]</span> </pre></div> </div> <p>So we already get quotient topologies (using the projection map as <code class="docutils literal notranslate"><span class="pre">f</span></code>). This wasn’t using that <code class="docutils literal notranslate"><span class="pre">topological_space</span> <span class="pre">X</span></code> is a complete lattice for all <code class="docutils literal notranslate"><span class="pre">X</span></code>. Let’s now see how all this structure proves the existence of the product topology by abstract non-sense. We considered the case of <code class="docutils literal notranslate"><span class="pre">ℝ</span> <span class="pre">→</span> <span class="pre">ℝ</span></code> above, but let’s now consider the general case of <code class="docutils literal notranslate"><span class="pre">Π</span> <span class="pre">i,</span> <span class="pre">X</span> <span class="pre">i</span></code> for some <code class="docutils literal notranslate"><span class="pre">ι</span> <span class="pre">:</span> <span class="pre">Type*</span></code> and <code class="docutils literal notranslate"><span class="pre">X</span> <span class="pre">:</span> <span class="pre">ι</span> <span class="pre">→</span> <span class="pre">Type*</span></code>. We want, for any topological space <code class="docutils literal notranslate"><span class="pre">Z</span></code> and any function <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">Z</span> <span class="pre">→</span> <span class="pre">Π</span> <span class="pre">i,</span> <span class="pre">X</span> <span class="pre">i</span></code>, that <code class="docutils literal notranslate"><span class="pre">f</span></code> is continuous if and only if <code class="docutils literal notranslate"><span class="pre">(fun</span> <span class="pre">x</span> <span class="pre">↦</span> <span class="pre">x</span> <span class="pre">i)</span> <span class="pre">∘</span> <span class="pre">f</span></code> is continuous. Let us explore that constraint “on papar” using notation <span class="math notranslate nohighlight">\(p_i\)</span> for the projection <code class="docutils literal notranslate"><span class="pre">(fun</span> <span class="pre">(x</span> <span class="pre">:</span> <span class="pre">Π</span> <span class="pre">i,</span> <span class="pre">X</span> <span class="pre">i)</span> <span class="pre">↦</span> <span class="pre">x</span> <span class="pre">i)</span></code>:</p> <div class="math notranslate nohighlight"> \[\begin{split}(∀ i, p_i ∘ f \text{ continuous}) &⇔ ∀ i, (p_i ∘ f)_* T_Z ≤ T_{X_i} \\ &⇔ ∀ i, (p_i)_* f_* T_Z ≤ T_{X_i}\\ &⇔ ∀ i, f_* T_Z ≤ (p_i)^*T_{X_i}\\ &⇔ f_* T_Z ≤ \inf \left[(p_i)^*T_{X_i}\right]\end{split}\]</div> <p>So we see that what is the topology we want on <code class="docutils literal notranslate"><span class="pre">Π</span> <span class="pre">i,</span> <span class="pre">X</span> <span class="pre">i</span></code>:</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">ι</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">)</span> <span class="o">(</span><span class="n">X</span> <span class="o">:</span> <span class="n">ι</span> <span class="bp">→</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">)</span> <span class="o">(</span><span class="n">T_X</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">i</span><span class="o">,</span> <span class="n">TopologicalSpace</span> <span class="bp"><|</span> <span class="n">X</span> <span class="n">i</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="k">Pi</span><span class="bp">.</span><span class="n">topologicalSpace</span> <span class="o">:</span> <span class="n">TopologicalSpace</span> <span class="o">(</span><span class="bp">∀</span> <span class="n">i</span><span class="o">,</span> <span class="n">X</span> <span class="n">i</span><span class="o">))</span> <span class="bp">=</span> <span class="bp">⨅</span> <span class="n">i</span><span class="o">,</span> <span class="n">TopologicalSpace.induced</span> <span class="o">(</span><span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">x</span> <span class="n">i</span><span class="o">)</span> <span class="o">(</span><span class="n">T_X</span> <span class="n">i</span><span class="o">)</span> <span class="o">:=</span> <span class="n">rfl</span> </pre></div> </div> <p>This ends our tour of how mathlib thinks that topological spaces fix defects of the theory of metric spaces by being a more functorial theory and having a complete lattice structure for any fixed type.</p> </section> <section id="separation-and-countability"> <h3><span class="section-number">8.3.2. </span>Separation and countability<a class="headerlink" href="#separation-and-countability" title="Permalink to this heading"></a></h3> <p>We saw that the category of topological spaces have very nice properties. The price to pay for this is existence of rather pathological topological spaces. There are a number of assumptions you can make on a topological space to ensure its behavior is closer to what metric spaces do. The most important is <code class="docutils literal notranslate"><span class="pre">t2_space</span></code>, also called “Hausdorff”, that will ensure that limits are unique. A stronger separation property is regularity that ensure that each point has a basis of closed neighborhood.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">[</span><span class="n">TopologicalSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">[</span><span class="n">T2Space</span> <span class="n">X</span><span class="o">]</span> <span class="o">{</span><span class="n">u</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">X</span><span class="o">}</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">ha</span> <span class="o">:</span> <span class="n">Tendsto</span> <span class="n">u</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">a</span><span class="o">))</span> <span class="o">(</span><span class="n">hb</span> <span class="o">:</span> <span class="n">Tendsto</span> <span class="n">u</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">b</span><span class="o">))</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">b</span> <span class="o">:=</span> <span class="n">tendsto_nhds_unique</span> <span class="n">ha</span> <span class="n">hb</span> <span class="kd">example</span> <span class="o">[</span><span class="n">TopologicalSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">[</span><span class="n">RegularSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">X</span><span class="o">)</span> <span class="o">:</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">a</span><span class="o">)</span><span class="bp">.</span><span class="n">HasBasis</span> <span class="o">(</span><span class="k">fun</span> <span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span> <span class="bp">=></span> <span class="n">s</span> <span class="bp">∈</span> <span class="bp">𝓝</span> <span class="n">a</span> <span class="bp">∧</span> <span class="n">IsClosed</span> <span class="n">s</span><span class="o">)</span> <span class="n">id</span> <span class="o">:=</span> <span class="n">closed_nhds_basis</span> <span class="n">a</span> </pre></div> </div> <p>Note that, in every topological space, each point has a basis of open neighborhood, by definition.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">[</span><span class="n">TopologicalSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">X</span><span class="o">}</span> <span class="o">:</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">x</span><span class="o">)</span><span class="bp">.</span><span class="n">HasBasis</span> <span class="o">(</span><span class="k">fun</span> <span class="n">t</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span> <span class="bp">=></span> <span class="n">t</span> <span class="bp">∈</span> <span class="bp">𝓝</span> <span class="n">x</span> <span class="bp">∧</span> <span class="n">IsOpen</span> <span class="n">t</span><span class="o">)</span> <span class="n">id</span> <span class="o">:=</span> <span class="n">nhds_basis_opens'</span> <span class="n">x</span> </pre></div> </div> <p>Our main goal is now to prove the basic theorem which allows extension by continuity. From Bourbaki’s general topology book, I.8.5, Theorem 1 (taking only the non-trivial implication):</p> <p>Let <span class="math notranslate nohighlight">\(X\)</span> be a topological space, <span class="math notranslate nohighlight">\(A\)</span> a dense subset of <span class="math notranslate nohighlight">\(X\)</span>, <span class="math notranslate nohighlight">\(f : A → Y\)</span> a continuous mapping of <span class="math notranslate nohighlight">\(A\)</span> into a regular space <span class="math notranslate nohighlight">\(Y\)</span>. If, for each <span class="math notranslate nohighlight">\(x\)</span> in <span class="math notranslate nohighlight">\(X\)</span>, <span class="math notranslate nohighlight">\(f(y)\)</span> tends to a limit in <span class="math notranslate nohighlight">\(Y\)</span> when <span class="math notranslate nohighlight">\(y\)</span> tends to <span class="math notranslate nohighlight">\(x\)</span> while remaining in <span class="math notranslate nohighlight">\(A\)</span> then there exists a continuous extension <span class="math notranslate nohighlight">\(φ\)</span> of <span class="math notranslate nohighlight">\(f\)</span> to <span class="math notranslate nohighlight">\(X\)</span>.</p> <p>Actually <code class="docutils literal notranslate"><span class="pre">mathlib</span></code> contains a more general version of the above lemma, <code class="docutils literal notranslate"><span class="pre">DenseInducing.continuousAt_extend</span></code>, but we’ll stick to Bourbaki’s version here.</p> <p>Remember that, given <code class="docutils literal notranslate"><span class="pre">A</span> <span class="pre">:</span> <span class="pre">Set</span> <span class="pre">X</span></code>, <code class="docutils literal notranslate"><span class="pre">↥A</span></code> is the subtype associated to <code class="docutils literal notranslate"><span class="pre">A</span></code>, and Lean will automatically insert that funny up arrow when needed. And the (inclusion) coercion map is <code class="docutils literal notranslate"><span class="pre">(↑)</span> <span class="pre">:</span> <span class="pre">A</span> <span class="pre">→</span> <span class="pre">X</span></code>. The assumption “tends to <span class="math notranslate nohighlight">\(x\)</span> while remaining in <span class="math notranslate nohighlight">\(A\)</span>” corresponds to the pull-back filter <code class="docutils literal notranslate"><span class="pre">comap</span> <span class="pre">(↑)</span> <span class="pre">(𝓝</span> <span class="pre">x)</span></code>.</p> <p>Let’s prove first an auxiliary lemma, extracted to simplify the context (in particular we don’t need Y to be a topological space here).</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">theorem</span> <span class="n">aux</span> <span class="o">{</span><span class="n">X</span> <span class="n">Y</span> <span class="n">A</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">TopologicalSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">{</span><span class="n">c</span> <span class="o">:</span> <span class="n">A</span> <span class="bp">→</span> <span class="n">X</span><span class="o">}</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">A</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">}</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">X</span><span class="o">}</span> <span class="o">{</span><span class="n">F</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">Y</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">Tendsto</span> <span class="n">f</span> <span class="o">(</span><span class="n">comap</span> <span class="n">c</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">x</span><span class="o">))</span> <span class="n">F</span><span class="o">)</span> <span class="o">{</span><span class="n">V'</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">Y</span><span class="o">}</span> <span class="o">(</span><span class="n">V'_in</span> <span class="o">:</span> <span class="n">V'</span> <span class="bp">∈</span> <span class="n">F</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">V</span> <span class="bp">∈</span> <span class="bp">𝓝</span> <span class="n">x</span><span class="o">,</span> <span class="n">IsOpen</span> <span class="n">V</span> <span class="bp">∧</span> <span class="n">c</span> <span class="bp">⁻¹'</span> <span class="n">V</span> <span class="bp">⊆</span> <span class="n">f</span> <span class="bp">⁻¹'</span> <span class="n">V'</span> <span class="o">:=</span> <span class="gr">sorry</span> </pre></div> </div> <p>Let’s now turn to the main proof of the extension by continuity theorem.</p> <p>When Lean needs a topology on <code class="docutils literal notranslate"><span class="pre">↥A</span></code> it will use the induced topology, thanks to the instance <code class="docutils literal notranslate"><span class="pre">subtype.topological_space</span></code>. This all happens automatically. The only relevant lemma is <code class="docutils literal notranslate"><span class="pre">nhds_induced</span> <span class="pre">(↑)</span> <span class="pre">:</span> <span class="pre">∀</span> <span class="pre">a</span> <span class="pre">:</span> <span class="pre">↥A,</span> <span class="pre">𝓝</span> <span class="pre">a</span> <span class="pre">=</span> <span class="pre">comap</span> <span class="pre">(↑)</span> <span class="pre">(𝓝</span> <span class="pre">↑a)</span></code> (this is actually a general lemma about induced topologies).</p> <p>The proof outline is:</p> <p>The main assumption and the axiom of choice give a function <code class="docutils literal notranslate"><span class="pre">φ</span></code> such that <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">x,</span> <span class="pre">Tendsto</span> <span class="pre">f</span> <span class="pre">(comap</span> <span class="pre">(↑)</span> <span class="pre">$</span> <span class="pre">𝓝</span> <span class="pre">x)</span> <span class="pre">(𝓝</span> <span class="pre">(φ</span> <span class="pre">x))</span></code> (because <code class="docutils literal notranslate"><span class="pre">Y</span></code> is Hausdorff, <code class="docutils literal notranslate"><span class="pre">φ</span></code> is entirely determined, but we won’t need that until we try to prove that <code class="docutils literal notranslate"><span class="pre">φ</span></code> indeed extends <code class="docutils literal notranslate"><span class="pre">f</span></code>).</p> <p>Let’s first prove <code class="docutils literal notranslate"><span class="pre">φ</span></code> is continuous. Fix any <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">:</span> <span class="pre">X</span></code>. Since <code class="docutils literal notranslate"><span class="pre">Y</span></code> is regular, it suffices to check that for every <em>closed</em> neighborhood <code class="docutils literal notranslate"><span class="pre">V'</span></code> of <code class="docutils literal notranslate"><span class="pre">φ</span> <span class="pre">x</span></code>, <code class="docutils literal notranslate"><span class="pre">φ</span> <span class="pre">⁻¹'</span> <span class="pre">V'</span> <span class="pre">∈</span> <span class="pre">𝓝</span> <span class="pre">x</span></code>. The limit assumption gives (through the auxiliary lemma above) some <code class="docutils literal notranslate"><span class="pre">V</span> <span class="pre">∈</span> <span class="pre">𝓝</span> <span class="pre">x</span></code> such <code class="docutils literal notranslate"><span class="pre">is_open</span> <span class="pre">V</span> <span class="pre">∧</span> <span class="pre">(↑)</span> <span class="pre">⁻¹'</span> <span class="pre">V</span> <span class="pre">⊆</span> <span class="pre">f</span> <span class="pre">⁻¹'</span> <span class="pre">V'</span></code>. Since <code class="docutils literal notranslate"><span class="pre">V</span> <span class="pre">∈</span> <span class="pre">𝓝</span> <span class="pre">x</span></code>, it suffices to prove <code class="docutils literal notranslate"><span class="pre">V</span> <span class="pre">⊆</span> <span class="pre">φ</span> <span class="pre">⁻¹'</span> <span class="pre">V'</span></code>, ie <code class="docutils literal notranslate"><span class="pre">∀</span> <span class="pre">y</span> <span class="pre">∈</span> <span class="pre">V,</span> <span class="pre">φ</span> <span class="pre">y</span> <span class="pre">∈</span> <span class="pre">V'</span></code>. Let’s fix <code class="docutils literal notranslate"><span class="pre">y</span></code> in <code class="docutils literal notranslate"><span class="pre">V</span></code>. Because <code class="docutils literal notranslate"><span class="pre">V</span></code> is <em>open</em>, it is a neighborhood of <code class="docutils literal notranslate"><span class="pre">y</span></code>. In particular <code class="docutils literal notranslate"><span class="pre">(↑)</span> <span class="pre">⁻¹'</span> <span class="pre">V</span> <span class="pre">∈</span> <span class="pre">comap</span> <span class="pre">(↑)</span> <span class="pre">(𝓝</span> <span class="pre">y)</span></code> and a fortiori <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">⁻¹'</span> <span class="pre">V'</span> <span class="pre">∈</span> <span class="pre">comap</span> <span class="pre">(↑)</span> <span class="pre">(𝓝</span> <span class="pre">y)</span></code>. In addition <code class="docutils literal notranslate"><span class="pre">comap</span> <span class="pre">(↑)$</span> <span class="pre">𝓝</span> <span class="pre">y</span> <span class="pre">≠</span> <span class="pre">⊥</span></code> because <code class="docutils literal notranslate"><span class="pre">A</span></code> is dense. Because we know <code class="docutils literal notranslate"><span class="pre">Tendsto</span> <span class="pre">f</span> <span class="pre">(comap</span> <span class="pre">(↑)</span> <span class="pre">$</span> <span class="pre">𝓝</span> <span class="pre">y)</span> <span class="pre">(𝓝</span> <span class="pre">(φ</span> <span class="pre">y))</span></code> this implies <code class="docutils literal notranslate"><span class="pre">φ</span> <span class="pre">y</span> <span class="pre">∈</span> <span class="pre">closure</span> <span class="pre">V'</span></code> and, since <code class="docutils literal notranslate"><span class="pre">V'</span></code> is closed, we have proved <code class="docutils literal notranslate"><span class="pre">φ</span> <span class="pre">y</span> <span class="pre">∈</span> <span class="pre">V'</span></code>.</p> <p>It remains to prove that <code class="docutils literal notranslate"><span class="pre">φ</span></code> extends <code class="docutils literal notranslate"><span class="pre">f</span></code>. This is were continuity of <code class="docutils literal notranslate"><span class="pre">f</span></code> enters the discussion, together with the fact that <code class="docutils literal notranslate"><span class="pre">Y</span></code> is Hausdorff.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">[</span><span class="n">TopologicalSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">[</span><span class="n">TopologicalSpace</span> <span class="n">Y</span><span class="o">]</span> <span class="o">[</span><span class="n">RegularSpace</span> <span class="n">Y</span><span class="o">]</span> <span class="o">{</span><span class="n">A</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hA</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span><span class="o">,</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">closure</span> <span class="n">A</span><span class="o">)</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">A</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">}</span> <span class="o">(</span><span class="n">f_cont</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="n">f</span><span class="o">)</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span> <span class="o">:</span> <span class="n">X</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">c</span> <span class="o">:</span> <span class="n">Y</span><span class="o">,</span> <span class="n">Tendsto</span> <span class="n">f</span> <span class="o">(</span><span class="n">comap</span> <span class="o">(</span><span class="bp">↑</span><span class="o">)</span> <span class="bp"><|</span> <span class="bp">𝓝</span> <span class="n">x</span><span class="o">)</span> <span class="bp"><|</span> <span class="bp">𝓝</span> <span class="n">c</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">φ</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">,</span> <span class="n">Continuous</span> <span class="n">φ</span> <span class="bp">∧</span> <span class="bp">∀</span> <span class="n">a</span> <span class="o">:</span> <span class="n">A</span><span class="o">,</span> <span class="n">φ</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">f</span> <span class="n">a</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="k">#check</span> <span class="bp">@</span><span class="n">HasBasis.tendsto_right_iff</span> </pre></div> </div> <p>In addition to separation property, the main kind of assumption you can make on a topological space to bring it closer to metric spaces is countability assumption. The main one is first countability asking that every point has a countable neighborhood basic. In particular this ensures that closure of sets can be understood using sequences.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">[</span><span class="n">TopologicalSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">[</span><span class="n">TopologicalSpace.FirstCountableTopology</span> <span class="n">X</span><span class="o">]</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">{</span><span class="n">a</span> <span class="o">:</span> <span class="n">X</span><span class="o">}</span> <span class="o">:</span> <span class="n">a</span> <span class="bp">∈</span> <span class="n">closure</span> <span class="n">s</span> <span class="bp">↔</span> <span class="bp">∃</span> <span class="n">u</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">X</span><span class="o">,</span> <span class="o">(</span><span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="n">u</span> <span class="n">n</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">)</span> <span class="bp">∧</span> <span class="n">Tendsto</span> <span class="n">u</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">a</span><span class="o">)</span> <span class="o">:=</span> <span class="n">mem_closure_iff_seq_limit</span> </pre></div> </div> </section> <section id="id5"> <h3><span class="section-number">8.3.3. </span>Compactness<a class="headerlink" href="#id5" title="Permalink to this heading"></a></h3> <p>Let us now discuss how compactness is defined for topological spaces. As usual there are several ways to think about it and mathlib goes for the filter version.</p> <p>We first need to define cluster points of filters. Given a filter <code class="docutils literal notranslate"><span class="pre">F</span></code> on a topological space <code class="docutils literal notranslate"><span class="pre">X</span></code>, a point <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">:</span> <span class="pre">X</span></code> is a cluster point of <code class="docutils literal notranslate"><span class="pre">F</span></code> if <code class="docutils literal notranslate"><span class="pre">F</span></code>, seen as a generalized set, has non-empty intersection with the generalized set of points that are close to <code class="docutils literal notranslate"><span class="pre">x</span></code>.</p> <p>Then we can say that a set <code class="docutils literal notranslate"><span class="pre">s</span></code> is compact if every nonempty generalized set <code class="docutils literal notranslate"><span class="pre">F</span></code> contained in <code class="docutils literal notranslate"><span class="pre">s</span></code>, ie such that <code class="docutils literal notranslate"><span class="pre">F</span> <span class="pre">≤</span> <span class="pre">𝓟</span> <span class="pre">s</span></code>, has a cluster point in <code class="docutils literal notranslate"><span class="pre">s</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">[</span><span class="n">TopologicalSpace</span> <span class="n">X</span><span class="o">]</span> <span class="kd">example</span> <span class="o">{</span><span class="n">F</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">X</span><span class="o">}</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">X</span><span class="o">}</span> <span class="o">:</span> <span class="n">ClusterPt</span> <span class="n">x</span> <span class="n">F</span> <span class="bp">↔</span> <span class="n">NeBot</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">x</span> <span class="bp">⊓</span> <span class="n">F</span><span class="o">)</span> <span class="o">:=</span> <span class="n">Iff.rfl</span> <span class="kd">example</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">:</span> <span class="n">IsCompact</span> <span class="n">s</span> <span class="bp">↔</span> <span class="bp">∀</span> <span class="o">(</span><span class="n">F</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">X</span><span class="o">)</span> <span class="o">[</span><span class="n">NeBot</span> <span class="n">F</span><span class="o">],</span> <span class="n">F</span> <span class="bp">≤</span> <span class="bp">𝓟</span> <span class="n">s</span> <span class="bp">→</span> <span class="bp">∃</span> <span class="n">a</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="n">ClusterPt</span> <span class="n">a</span> <span class="n">F</span> <span class="o">:=</span> <span class="n">Iff.rfl</span> </pre></div> </div> <p>For instance if <code class="docutils literal notranslate"><span class="pre">F</span></code> is <code class="docutils literal notranslate"><span class="pre">map</span> <span class="pre">u</span> <span class="pre">at_top</span></code>, the image under <code class="docutils literal notranslate"><span class="pre">u</span> <span class="pre">:</span> <span class="pre">ℕ</span> <span class="pre">→</span> <span class="pre">X</span></code> of <code class="docutils literal notranslate"><span class="pre">at_top</span></code>, the generalized set of very large natural numbers, then the assumption <code class="docutils literal notranslate"><span class="pre">F</span> <span class="pre">≤</span> <span class="pre">𝓟</span> <span class="pre">s</span></code> means that <code class="docutils literal notranslate"><span class="pre">u</span> <span class="pre">n</span></code> belongs to <code class="docutils literal notranslate"><span class="pre">s</span></code> for <code class="docutils literal notranslate"><span class="pre">n</span></code> large enough. Saying that <code class="docutils literal notranslate"><span class="pre">x</span></code> is a cluster point of <code class="docutils literal notranslate"><span class="pre">map</span> <span class="pre">u</span> <span class="pre">at_top</span></code> says the image of very large numbers intersects the set of points that are close to <code class="docutils literal notranslate"><span class="pre">x</span></code>. In case <code class="docutils literal notranslate"><span class="pre">𝓝</span> <span class="pre">x</span></code> has a countable basis, we can interpret this as saying that <code class="docutils literal notranslate"><span class="pre">u</span></code> has a subsequence converging to <code class="docutils literal notranslate"><span class="pre">x</span></code>, and we get back what compactness looks like in metric spaces.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">[</span><span class="n">TopologicalSpace.FirstCountableTopology</span> <span class="n">X</span><span class="o">]</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">{</span><span class="n">u</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hs</span> <span class="o">:</span> <span class="n">IsCompact</span> <span class="n">s</span><span class="o">)</span> <span class="o">(</span><span class="n">hu</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span><span class="o">,</span> <span class="n">u</span> <span class="n">n</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">a</span> <span class="bp">∈</span> <span class="n">s</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">φ</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">ℕ</span><span class="o">,</span> <span class="n">StrictMono</span> <span class="n">φ</span> <span class="bp">∧</span> <span class="n">Tendsto</span> <span class="o">(</span><span class="n">u</span> <span class="bp">∘</span> <span class="n">φ</span><span class="o">)</span> <span class="n">atTop</span> <span class="o">(</span><span class="bp">𝓝</span> <span class="n">a</span><span class="o">)</span> <span class="o">:=</span> <span class="n">hs.tendsto_subseq</span> <span class="n">hu</span> </pre></div> </div> <p>Cluster points behave nicely with continuous functions.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">[</span><span class="n">TopologicalSpace</span> <span class="n">Y</span><span class="o">]</span> <span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">X</span><span class="o">}</span> <span class="o">{</span><span class="n">F</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">X</span><span class="o">}</span> <span class="o">{</span><span class="n">G</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">Y</span><span class="o">}</span> <span class="o">(</span><span class="n">H</span> <span class="o">:</span> <span class="n">ClusterPt</span> <span class="n">x</span> <span class="n">F</span><span class="o">)</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">}</span> <span class="o">(</span><span class="n">hfx</span> <span class="o">:</span> <span class="n">ContinuousAt</span> <span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">Tendsto</span> <span class="n">f</span> <span class="n">F</span> <span class="n">G</span><span class="o">)</span> <span class="o">:</span> <span class="n">ClusterPt</span> <span class="o">(</span><span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="n">G</span> <span class="o">:=</span> <span class="n">ClusterPt.map</span> <span class="n">H</span> <span class="n">hfx</span> <span class="n">hf</span> </pre></div> </div> <p>As an exercise, we will prove that the image of a compact set under a continuous map is compact. In addition to what we saw already, you should use <code class="docutils literal notranslate"><span class="pre">Filter.push_pull</span></code> and <code class="docutils literal notranslate"><span class="pre">ne_bot.of_map</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">[</span><span class="n">TopologicalSpace</span> <span class="n">Y</span><span class="o">]</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">Y</span><span class="o">}</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="n">f</span><span class="o">)</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hs</span> <span class="o">:</span> <span class="n">IsCompact</span> <span class="n">s</span><span class="o">)</span> <span class="o">:</span> <span class="n">IsCompact</span> <span class="o">(</span><span class="n">f</span> <span class="bp">''</span> <span class="n">s</span><span class="o">)</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">intro</span> <span class="n">F</span> <span class="n">F_ne</span> <span class="n">F_le</span> <span class="k">have</span> <span class="n">map_eq</span> <span class="o">:</span> <span class="n">map</span> <span class="n">f</span> <span class="o">(</span><span class="bp">𝓟</span> <span class="n">s</span> <span class="bp">⊓</span> <span class="n">comap</span> <span class="n">f</span> <span class="n">F</span><span class="o">)</span> <span class="bp">=</span> <span class="bp">𝓟</span> <span class="o">(</span><span class="n">f</span> <span class="bp">''</span> <span class="n">s</span><span class="o">)</span> <span class="bp">⊓</span> <span class="n">F</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="n">Hne</span> <span class="o">:</span> <span class="o">(</span><span class="bp">𝓟</span> <span class="n">s</span> <span class="bp">⊓</span> <span class="n">comap</span> <span class="n">f</span> <span class="n">F</span><span class="o">)</span><span class="bp">.</span><span class="n">NeBot</span> <span class="o">:=</span> <span class="kd">by</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="n">Hle</span> <span class="o">:</span> <span class="bp">𝓟</span> <span class="n">s</span> <span class="bp">⊓</span> <span class="n">comap</span> <span class="n">f</span> <span class="n">F</span> <span class="bp">≤</span> <span class="bp">𝓟</span> <span class="n">s</span> <span class="o">:=</span> <span class="n">inf_le_left</span> <span class="gr">sorry</span> </pre></div> </div> <p>One can also express compactness in terms of open covers: <code class="docutils literal notranslate"><span class="pre">s</span></code> is compact if every family of open sets that cover <code class="docutils literal notranslate"><span class="pre">s</span></code> has a finite covering sub-family.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">ι</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">{</span><span class="n">s</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">}</span> <span class="o">(</span><span class="n">hs</span> <span class="o">:</span> <span class="n">IsCompact</span> <span class="n">s</span><span class="o">)</span> <span class="o">(</span><span class="n">U</span> <span class="o">:</span> <span class="n">ι</span> <span class="bp">→</span> <span class="n">Set</span> <span class="n">X</span><span class="o">)</span> <span class="o">(</span><span class="n">hUo</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">i</span><span class="o">,</span> <span class="n">IsOpen</span> <span class="o">(</span><span class="n">U</span> <span class="n">i</span><span class="o">))</span> <span class="o">(</span><span class="n">hsU</span> <span class="o">:</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="bp">⋃</span> <span class="n">i</span><span class="o">,</span> <span class="n">U</span> <span class="n">i</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">t</span> <span class="o">:</span> <span class="n">Finset</span> <span class="n">ι</span><span class="o">,</span> <span class="n">s</span> <span class="bp">⊆</span> <span class="bp">⋃</span> <span class="n">i</span> <span class="bp">∈</span> <span class="n">t</span><span class="o">,</span> <span class="n">U</span> <span class="n">i</span> <span class="o">:=</span> <span class="n">hs.elim_finite_subcover</span> <span class="n">U</span> <span class="n">hUo</span> <span class="n">hsU</span> </pre></div> </div> <p>A topological space <code class="docutils literal notranslate"><span class="pre">X</span></code> is compact if <code class="docutils literal notranslate"><span class="pre">(univ</span> <span class="pre">:</span> <span class="pre">Set</span> <span class="pre">X)</span></code> is compact.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">[</span><span class="n">CompactSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">:</span> <span class="n">IsCompact</span> <span class="o">(</span><span class="n">univ</span> <span class="o">:</span> <span class="n">Set</span> <span class="n">X</span><span class="o">)</span> <span class="o">:=</span> <span class="n">isCompact_univ</span> </pre></div> </div> </section> </section> </section> </div> </div> <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> <a href="C07_Hierarchies.html" class="btn btn-neutral float-left" title="7. Hierarchies" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> <a href="C09_Differential_Calculus.html" class="btn btn-neutral float-right" title="9. Differential Calculus" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> </div> <hr/> <div role="contentinfo"> <p>© Copyright 2020, Jeremy Avigad, Kevin Buzzard, Robert Y. Lewis, Patrick Massot.</p> </div> Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. </footer> </div> </div> </section> </div> <script> jQuery(function () { SphinxRtdTheme.Navigation.enable(true); }); </script> </body> </html>
-
-
-
@@ -0,0 +1,476 @@<!DOCTYPE html> <html class="writer-html5" lang="en" > <head> <meta charset="utf-8" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>9. Differential Calculus — Mathematics in Lean 0.1 documentation</title> <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> <link rel="stylesheet" href="_static/css/custom.css" type="text/css" /> <link rel="shortcut icon" href="_static/favicon.ico"/> <!--[if lt IE 9]> <script src="_static/js/html5shiv.min.js"></script> <![endif]--> <script src="_static/jquery.js"></script> <script src="_static/_sphinx_javascript_frameworks_compat.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script src="_static/doctools.js"></script> <script src="_static/sphinx_highlight.js"></script> <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> <script src="_static/js/theme.js"></script> <link rel="index" title="Index" href="genindex.html" /> <link rel="search" title="Search" href="search.html" /> <link rel="next" title="Index" href="genindex.html" /> <link rel="prev" title="8. Topology" href="C08_Topology.html" /> </head> <body class="wy-body-for-nav"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search" > <a href="index.html" class="icon icon-home"> Mathematics in Lean </a> <div role="search"> <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> <ul class="current"> <li class="toctree-l1"><a class="reference internal" href="C01_Introduction.html">1. Introduction</a></li> <li class="toctree-l1"><a class="reference internal" href="C02_Basics.html">2. Basics</a></li> <li class="toctree-l1"><a class="reference internal" href="C03_Logic.html">3. Logic</a></li> <li class="toctree-l1"><a class="reference internal" href="C04_Sets_and_Functions.html">4. Sets and Functions</a></li> <li class="toctree-l1"><a class="reference internal" href="C05_Number_Theory.html">5. Number Theory</a></li> <li class="toctree-l1"><a class="reference internal" href="C06_Structures.html">6. Structures</a></li> <li class="toctree-l1"><a class="reference internal" href="C07_Hierarchies.html">7. Hierarchies</a></li> <li class="toctree-l1"><a class="reference internal" href="C08_Topology.html">8. Topology</a></li> <li class="toctree-l1 current"><a class="current reference internal" href="#">9. Differential Calculus</a><ul> <li class="toctree-l2"><a class="reference internal" href="#elementary-differential-calculus">9.1. Elementary Differential Calculus</a></li> <li class="toctree-l2"><a class="reference internal" href="#differential-calculus-in-normed-spaces">9.2. Differential Calculus in Normed Spaces</a><ul> <li class="toctree-l3"><a class="reference internal" href="#id3">9.2.1. Normed spaces</a></li> <li class="toctree-l3"><a class="reference internal" href="#continuous-linear-maps">9.2.2. Continuous linear maps</a></li> <li class="toctree-l3"><a class="reference internal" href="#asymptotic-comparisons">9.2.3. Asymptotic comparisons</a></li> <li class="toctree-l3"><a class="reference internal" href="#differentiability">9.2.4. Differentiability</a></li> </ul> </li> </ul> </li> </ul> <ul> <li class="toctree-l1"><a class="reference internal" href="genindex.html">Index</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="index.html">Mathematics in Lean</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="Page navigation"> <ul class="wy-breadcrumbs"> <li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li> <li class="breadcrumb-item active"><span class="section-number">9. </span>Differential Calculus</li> <li class="wy-breadcrumbs-aside"> <a href="_sources/C09_Differential_Calculus.rst.txt" rel="nofollow"> View page source</a> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <span class="target" id="differential-calculus"></span><section id="index-0"> <span id="id1"></span><h1><span class="section-number">9. </span>Differential Calculus<a class="headerlink" href="#index-0" title="Permalink to this heading"></a></h1> <p>We now consider the formalization of notions from <em>analysis</em>, starting with differentiation in this chapter and turning integration and measure theory in the next. In <a class="reference internal" href="#elementary-differential-calculus"><span class="std std-numref">Section 9.1</span></a>, we stick with the setting of functions from the real numbers to the real numbers, which is familiar from any introductory calculus class. In <a class="reference internal" href="#normed-spaces"><span class="std std-numref">Section 9.2</span></a>, we then consider the notion of a derivative in a much broader setting.</p> <section id="elementary-differential-calculus"> <span id="index-1"></span><span id="id2"></span><h2><span class="section-number">9.1. </span>Elementary Differential Calculus<a class="headerlink" href="#elementary-differential-calculus" title="Permalink to this heading"></a></h2> <p>Let <code class="docutils literal notranslate"><span class="pre">f</span></code> be a function from the reals to the reals. There is a difference between talking about the derivative of <code class="docutils literal notranslate"><span class="pre">f</span></code> at a single point and talking about the derivative function. In mathlib, the first notion is represented as follows.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">open</span> <span class="n">Real</span> <span class="sd">/-- The sin function has derivative 1 at 0. -/</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">HasDerivAt</span> <span class="n">sin</span> <span class="mi">1</span> <span class="mi">0</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simpa</span> <span class="n">using</span> <span class="n">hasDerivAt_sin</span> <span class="mi">0</span> </pre></div> </div> <p>We can also express that <code class="docutils literal notranslate"><span class="pre">f</span></code> is differentiable at a point without specifying its derivative there by writing <code class="docutils literal notranslate"><span class="pre">differentiable_at</span> <span class="pre">ℝ</span></code>. We specify <code class="docutils literal notranslate"><span class="pre">ℝ</span></code> explicitly because in a slightly more general context, when talking about functions from <code class="docutils literal notranslate"><span class="pre">ℂ</span></code> to <code class="docutils literal notranslate"><span class="pre">ℂ</span></code>, we want to be able to distinguish between being differentiable in the real sense and being differentiable in the sense of the complex derivative.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">:</span> <span class="n">DifferentiableAt</span> <span class="n">ℝ</span> <span class="n">sin</span> <span class="n">x</span> <span class="o">:=</span> <span class="o">(</span><span class="n">hasDerivAt_sin</span> <span class="n">x</span><span class="o">)</span><span class="bp">.</span><span class="n">differentiableAt</span> </pre></div> </div> <p>It would be inconvenient to have to provide a proof of differentiability every time we want to refer to a derivative. So mathlib provides a function <code class="docutils literal notranslate"><span class="pre">deriv</span> <span class="pre">f</span> <span class="pre">:</span> <span class="pre">ℝ</span> <span class="pre">→</span> <span class="pre">ℝ</span></code> that is defined for any function <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">ℝ</span> <span class="pre">→</span> <span class="pre">ℝ</span></code> but is defined to take the value <code class="docutils literal notranslate"><span class="pre">0</span></code> at any point where <code class="docutils literal notranslate"><span class="pre">f</span></code> is not differentiable.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">{</span><span class="n">x</span> <span class="n">a</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">HasDerivAt</span> <span class="n">f</span> <span class="n">a</span> <span class="n">x</span><span class="o">)</span> <span class="o">:</span> <span class="n">deriv</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">a</span> <span class="o">:=</span> <span class="n">h.deriv</span> <span class="kd">example</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">¬</span><span class="n">DifferentiableAt</span> <span class="n">ℝ</span> <span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="o">:</span> <span class="n">deriv</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="n">deriv_zero_of_not_differentiableAt</span> <span class="n">h</span> </pre></div> </div> <p>Of course there are many lemmas about <code class="docutils literal notranslate"><span class="pre">deriv</span></code> that do require differentiability assumptions. For instance, you should think about a counterexample to the next lemma without the differentiability assumptions.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">f</span> <span class="n">g</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">DifferentiableAt</span> <span class="n">ℝ</span> <span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="o">(</span><span class="n">hg</span> <span class="o">:</span> <span class="n">DifferentiableAt</span> <span class="n">ℝ</span> <span class="n">g</span> <span class="n">x</span><span class="o">)</span> <span class="o">:</span> <span class="n">deriv</span> <span class="o">(</span><span class="n">f</span> <span class="bp">+</span> <span class="n">g</span><span class="o">)</span> <span class="n">x</span> <span class="bp">=</span> <span class="n">deriv</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">deriv</span> <span class="n">g</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">deriv_add</span> <span class="n">hf</span> <span class="n">hg</span> </pre></div> </div> <p>Interestingly, however, there are statements that can avoid differentiability assumptions by taking advantage of the fact that the value of <code class="docutils literal notranslate"><span class="pre">deriv</span></code> defaults to zero when the function is not differentiable. So making sense of the following statement requires knowing the precise definition of <code class="docutils literal notranslate"><span class="pre">deriv</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">{</span><span class="n">a</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="n">IsLocalMin</span> <span class="n">f</span> <span class="n">a</span><span class="o">)</span> <span class="o">:</span> <span class="n">deriv</span> <span class="n">f</span> <span class="n">a</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="n">h.deriv_eq_zero</span> </pre></div> </div> <p>We can eve state Rolle’s theorem without any differentiability assumptions, which seems even weirder.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">hab</span> <span class="o">:</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">b</span><span class="o">)</span> <span class="o">(</span><span class="n">hfc</span> <span class="o">:</span> <span class="n">ContinuousOn</span> <span class="n">f</span> <span class="o">(</span><span class="n">Icc</span> <span class="n">a</span> <span class="n">b</span><span class="o">))</span> <span class="o">(</span><span class="n">hfI</span> <span class="o">:</span> <span class="n">f</span> <span class="n">a</span> <span class="bp">=</span> <span class="n">f</span> <span class="n">b</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">c</span> <span class="bp">∈</span> <span class="n">Ioo</span> <span class="n">a</span> <span class="n">b</span><span class="o">,</span> <span class="n">deriv</span> <span class="n">f</span> <span class="n">c</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="n">exists_deriv_eq_zero</span> <span class="n">f</span> <span class="n">hab</span> <span class="n">hfc</span> <span class="n">hfI</span> </pre></div> </div> <p>Of course, this trick does not work for the general mean value theorem.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">→</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">{</span><span class="n">a</span> <span class="n">b</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">hab</span> <span class="o">:</span> <span class="n">a</span> <span class="bp"><</span> <span class="n">b</span><span class="o">)</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">ContinuousOn</span> <span class="n">f</span> <span class="o">(</span><span class="n">Icc</span> <span class="n">a</span> <span class="n">b</span><span class="o">))</span> <span class="o">(</span><span class="n">hf'</span> <span class="o">:</span> <span class="n">DifferentiableOn</span> <span class="n">ℝ</span> <span class="n">f</span> <span class="o">(</span><span class="n">Ioo</span> <span class="n">a</span> <span class="n">b</span><span class="o">))</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">c</span> <span class="bp">∈</span> <span class="n">Ioo</span> <span class="n">a</span> <span class="n">b</span><span class="o">,</span> <span class="n">deriv</span> <span class="n">f</span> <span class="n">c</span> <span class="bp">=</span> <span class="o">(</span><span class="n">f</span> <span class="n">b</span> <span class="bp">-</span> <span class="n">f</span> <span class="n">a</span><span class="o">)</span> <span class="bp">/</span> <span class="o">(</span><span class="n">b</span> <span class="bp">-</span> <span class="n">a</span><span class="o">)</span> <span class="o">:=</span> <span class="n">exists_deriv_eq_slope</span> <span class="n">f</span> <span class="n">hab</span> <span class="n">hf</span> <span class="n">hf'</span> </pre></div> </div> <p>Lean can automatically compute some simple derivatives using the <code class="docutils literal notranslate"><span class="pre">simp</span></code> tactic.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">deriv</span> <span class="o">(</span><span class="k">fun</span> <span class="n">x</span> <span class="o">:</span> <span class="n">ℝ</span> <span class="bp">↦</span> <span class="n">x</span> <span class="bp">^</span> <span class="mi">5</span><span class="o">)</span> <span class="mi">6</span> <span class="bp">=</span> <span class="mi">5</span> <span class="bp">*</span> <span class="mi">6</span> <span class="bp">^</span> <span class="mi">4</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">deriv</span> <span class="n">sin</span> <span class="n">π</span> <span class="bp">=</span> <span class="bp">-</span><span class="mi">1</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">simp</span> </pre></div> </div> </section> <section id="differential-calculus-in-normed-spaces"> <span id="normed-spaces"></span><span id="index-2"></span><h2><span class="section-number">9.2. </span>Differential Calculus in Normed Spaces<a class="headerlink" href="#differential-calculus-in-normed-spaces" title="Permalink to this heading"></a></h2> <section id="id3"> <h3><span class="section-number">9.2.1. </span>Normed spaces<a class="headerlink" href="#id3" title="Permalink to this heading"></a></h3> <p>Differentiation can be generalized beyond <code class="docutils literal notranslate"><span class="pre">ℝ</span></code> using the notion of a <em>normed vector space</em>, which encapsulates both direction and distance. We start with the notion of a <em>normed group</em>, which as an additive commutative group equipped with a real-valued norm function satisfying the following conditions.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="n">E</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NormedAddCommGroup</span> <span class="n">E</span><span class="o">]</span> <span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">E</span><span class="o">)</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="bp">‖</span><span class="n">x</span><span class="bp">‖</span> <span class="o">:=</span> <span class="n">norm_nonneg</span> <span class="n">x</span> <span class="kd">example</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">E</span><span class="o">}</span> <span class="o">:</span> <span class="bp">‖</span><span class="n">x</span><span class="bp">‖</span> <span class="bp">=</span> <span class="mi">0</span> <span class="bp">↔</span> <span class="n">x</span> <span class="bp">=</span> <span class="mi">0</span> <span class="o">:=</span> <span class="n">norm_eq_zero</span> <span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">E</span><span class="o">)</span> <span class="o">:</span> <span class="bp">‖</span><span class="n">x</span> <span class="bp">+</span> <span class="n">y</span><span class="bp">‖</span> <span class="bp">≤</span> <span class="bp">‖</span><span class="n">x</span><span class="bp">‖</span> <span class="bp">+</span> <span class="bp">‖</span><span class="n">y</span><span class="bp">‖</span> <span class="o">:=</span> <span class="n">norm_add_le</span> <span class="n">x</span> <span class="n">y</span> </pre></div> </div> <p>Every normed space is a metric space with distance function <span class="math notranslate nohighlight">\(d(x, y) = \| x - y \|\)</span>, and hence it is also a topological space. Lean and mathlib know this.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">:</span> <span class="n">MetricSpace</span> <span class="n">E</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">infer_instance</span> <span class="kd">example</span> <span class="o">{</span><span class="n">X</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">TopologicalSpace</span> <span class="n">X</span><span class="o">]</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">X</span> <span class="bp">→</span> <span class="n">E</span><span class="o">}</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="n">f</span><span class="o">)</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="bp">‖</span><span class="n">f</span> <span class="n">x</span><span class="bp">‖</span> <span class="o">:=</span> <span class="n">hf.norm</span> </pre></div> </div> <p>In order to use the notion of a norm with concepts from linear algebra, we add the assumption <code class="docutils literal notranslate"><span class="pre">normed_space</span> <span class="pre">ℝ</span> <span class="pre">E</span></code> on top of <code class="docutils literal notranslate"><span class="pre">normed_add_group</span> <span class="pre">E</span></code>. This stipulates that <code class="docutils literal notranslate"><span class="pre">E</span></code> is a vector space over <code class="docutils literal notranslate"><span class="pre">ℝ</span></code> and that scalar multiplication satisfies the following condition.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">[</span><span class="n">NormedSpace</span> <span class="n">ℝ</span> <span class="n">E</span><span class="o">]</span> <span class="kd">example</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">E</span><span class="o">)</span> <span class="o">:</span> <span class="bp">‖</span><span class="n">a</span> <span class="bp">•</span> <span class="n">x</span><span class="bp">‖</span> <span class="bp">=</span> <span class="bp">|</span><span class="n">a</span><span class="bp">|</span> <span class="bp">*</span> <span class="bp">‖</span><span class="n">x</span><span class="bp">‖</span> <span class="o">:=</span> <span class="n">norm_smul</span> <span class="n">a</span> <span class="n">x</span> </pre></div> </div> <p>A complete normed space is known as a <em>Banach space</em>. Every finite-dimensional vector space is complete.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">[</span><span class="n">FiniteDimensional</span> <span class="n">ℝ</span> <span class="n">E</span><span class="o">]</span> <span class="o">:</span> <span class="n">CompleteSpace</span> <span class="n">E</span> <span class="o">:=</span> <span class="kd">by</span> <span class="n">infer_instance</span> </pre></div> </div> <p>In all the previous examples, we used the real numbers as the base field. More generally, we can make sense of calculus with a vector space over any <em>non-discrete normed field</em>. These are fields that are equipped with a real-valued norm that is multiplicative and has the property that not every element has norm zero or one (equivalently, there is an element whose norm is bigger than one).</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="bp">𝕜</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">)</span> <span class="o">[</span><span class="n">NontriviallyNormedField</span> <span class="bp">𝕜</span><span class="o">]</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="bp">𝕜</span><span class="o">)</span> <span class="o">:</span> <span class="bp">‖</span><span class="n">x</span> <span class="bp">*</span> <span class="n">y</span><span class="bp">‖</span> <span class="bp">=</span> <span class="bp">‖</span><span class="n">x</span><span class="bp">‖</span> <span class="bp">*</span> <span class="bp">‖</span><span class="n">y</span><span class="bp">‖</span> <span class="o">:=</span> <span class="n">norm_mul</span> <span class="n">x</span> <span class="n">y</span> <span class="kd">example</span> <span class="o">(</span><span class="bp">𝕜</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">)</span> <span class="o">[</span><span class="n">NontriviallyNormedField</span> <span class="bp">𝕜</span><span class="o">]</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">x</span> <span class="o">:</span> <span class="bp">𝕜</span><span class="o">,</span> <span class="mi">1</span> <span class="bp"><</span> <span class="bp">‖</span><span class="n">x</span><span class="bp">‖</span> <span class="o">:=</span> <span class="n">NormedField.exists_one_lt_norm</span> <span class="bp">𝕜</span> </pre></div> </div> <p>A finite-dimensional vector space over a nondiscrete normed field is complete as long as the field itself is complete.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="bp">𝕜</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">)</span> <span class="o">[</span><span class="n">NontriviallyNormedField</span> <span class="bp">𝕜</span><span class="o">]</span> <span class="o">(</span><span class="n">E</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">)</span> <span class="o">[</span><span class="n">NormedAddCommGroup</span> <span class="n">E</span><span class="o">]</span> <span class="o">[</span><span class="n">NormedSpace</span> <span class="bp">𝕜</span> <span class="n">E</span><span class="o">]</span> <span class="o">[</span><span class="n">CompleteSpace</span> <span class="bp">𝕜</span><span class="o">]</span> <span class="o">[</span><span class="n">FiniteDimensional</span> <span class="bp">𝕜</span> <span class="n">E</span><span class="o">]</span> <span class="o">:</span> <span class="n">CompleteSpace</span> <span class="n">E</span> <span class="o">:=</span> <span class="n">FiniteDimensional.complete</span> <span class="bp">𝕜</span> <span class="n">E</span> </pre></div> </div> </section> <section id="continuous-linear-maps"> <h3><span class="section-number">9.2.2. </span>Continuous linear maps<a class="headerlink" href="#continuous-linear-maps" title="Permalink to this heading"></a></h3> <p>We now turn to the morphisms in the category of normed spaces, namely, continuous linear maps. In mathlib, the type of <code class="docutils literal notranslate"><span class="pre">𝕜</span></code>-linear continuous maps between normed spaces <code class="docutils literal notranslate"><span class="pre">E</span></code> and <code class="docutils literal notranslate"><span class="pre">F</span></code> is written <code class="docutils literal notranslate"><span class="pre">E</span> <span class="pre">→L[𝕜]</span> <span class="pre">F</span></code>. They are implemented as <em>bundled maps</em>, which means that an element of this type a structure that that includes the function itself and the properties of being linear and continuous. Lean will insert a coercion so that a continuous linear map can be treated as a function.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="bp">𝕜</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NontriviallyNormedField</span> <span class="bp">𝕜</span><span class="o">]</span> <span class="o">{</span><span class="n">E</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NormedAddCommGroup</span> <span class="n">E</span><span class="o">]</span> <span class="o">[</span><span class="n">NormedSpace</span> <span class="bp">𝕜</span> <span class="n">E</span><span class="o">]</span> <span class="o">{</span><span class="n">F</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NormedAddCommGroup</span> <span class="n">F</span><span class="o">]</span> <span class="o">[</span><span class="n">NormedSpace</span> <span class="bp">𝕜</span> <span class="n">F</span><span class="o">]</span> <span class="kd">example</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">E</span> <span class="o">:=</span> <span class="n">ContinuousLinearMap.id</span> <span class="bp">𝕜</span> <span class="n">E</span> <span class="kd">example</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">F</span><span class="o">)</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span> <span class="n">F</span> <span class="o">:=</span> <span class="n">f</span> <span class="kd">example</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">F</span><span class="o">)</span> <span class="o">:</span> <span class="n">Continuous</span> <span class="n">f</span> <span class="o">:=</span> <span class="n">f.cont</span> <span class="kd">example</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">F</span><span class="o">)</span> <span class="o">(</span><span class="n">x</span> <span class="n">y</span> <span class="o">:</span> <span class="n">E</span><span class="o">)</span> <span class="o">:</span> <span class="n">f</span> <span class="o">(</span><span class="n">x</span> <span class="bp">+</span> <span class="n">y</span><span class="o">)</span> <span class="bp">=</span> <span class="n">f</span> <span class="n">x</span> <span class="bp">+</span> <span class="n">f</span> <span class="n">y</span> <span class="o">:=</span> <span class="n">f.map_add</span> <span class="n">x</span> <span class="n">y</span> <span class="kd">example</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">F</span><span class="o">)</span> <span class="o">(</span><span class="n">a</span> <span class="o">:</span> <span class="bp">𝕜</span><span class="o">)</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">E</span><span class="o">)</span> <span class="o">:</span> <span class="n">f</span> <span class="o">(</span><span class="n">a</span> <span class="bp">•</span> <span class="n">x</span><span class="o">)</span> <span class="bp">=</span> <span class="n">a</span> <span class="bp">•</span> <span class="n">f</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">f.map_smul</span> <span class="n">a</span> <span class="n">x</span> </pre></div> </div> <p>Continuous linear maps have an operator norm that is characterized by the following properties.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">F</span><span class="o">)</span> <span class="kd">example</span> <span class="o">(</span><span class="n">x</span> <span class="o">:</span> <span class="n">E</span><span class="o">)</span> <span class="o">:</span> <span class="bp">‖</span><span class="n">f</span> <span class="n">x</span><span class="bp">‖</span> <span class="bp">≤</span> <span class="bp">‖</span><span class="n">f</span><span class="bp">‖</span> <span class="bp">*</span> <span class="bp">‖</span><span class="n">x</span><span class="bp">‖</span> <span class="o">:=</span> <span class="n">f.le_op_norm</span> <span class="n">x</span> <span class="kd">example</span> <span class="o">{</span><span class="n">M</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">}</span> <span class="o">(</span><span class="n">hMp</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp">≤</span> <span class="n">M</span><span class="o">)</span> <span class="o">(</span><span class="n">hM</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span><span class="o">,</span> <span class="bp">‖</span><span class="n">f</span> <span class="n">x</span><span class="bp">‖</span> <span class="bp">≤</span> <span class="n">M</span> <span class="bp">*</span> <span class="bp">‖</span><span class="n">x</span><span class="bp">‖</span><span class="o">)</span> <span class="o">:</span> <span class="bp">‖</span><span class="n">f</span><span class="bp">‖</span> <span class="bp">≤</span> <span class="n">M</span> <span class="o">:=</span> <span class="n">f.op_norm_le_bound</span> <span class="n">hMp</span> <span class="n">hM</span> </pre></div> </div> <p>There is also a notion of bundled continuous linear <em>isomorphism</em>. Their type of such isomorphisms is <code class="docutils literal notranslate"><span class="pre">E</span> <span class="pre">≃L[𝕜]</span> <span class="pre">F</span></code>.</p> <p>As a challenging exercise, you can prove the Banach-Steinhaus theorem, also known as the Uniform Boundedness Principle. The principle states that a family of continuous linear maps from a Banach space into a normed space is pointwise bounded, then the norms of these linear maps are uniformly bounded. The main ingredient is Baire’s theorem <code class="docutils literal notranslate"><span class="pre">nonempty_interior_of_Union_of_closed.</span></code> (You proved a version of this in the topology chapter.) Minor ingredients include <code class="docutils literal notranslate"><span class="pre">continuous_linear_map.op_norm_le_of_shell</span></code>, <code class="docutils literal notranslate"><span class="pre">interior_subset</span></code> and <code class="docutils literal notranslate"><span class="pre">interior_Inter_subset</span></code> and <code class="docutils literal notranslate"><span class="pre">is_closed_le</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="bp">𝕜</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NontriviallyNormedField</span> <span class="bp">𝕜</span><span class="o">]</span> <span class="o">{</span><span class="n">E</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NormedAddCommGroup</span> <span class="n">E</span><span class="o">]</span> <span class="o">[</span><span class="n">NormedSpace</span> <span class="bp">𝕜</span> <span class="n">E</span><span class="o">]</span> <span class="o">{</span><span class="n">F</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NormedAddCommGroup</span> <span class="n">F</span><span class="o">]</span> <span class="o">[</span><span class="n">NormedSpace</span> <span class="bp">𝕜</span> <span class="n">F</span><span class="o">]</span> <span class="kn">open</span> <span class="n">Metric</span> <span class="kd">example</span> <span class="o">{</span><span class="n">ι</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">CompleteSpace</span> <span class="n">E</span><span class="o">]</span> <span class="o">{</span><span class="n">g</span> <span class="o">:</span> <span class="n">ι</span> <span class="bp">→</span> <span class="n">E</span> <span class="bp">→</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">F</span><span class="o">}</span> <span class="o">(</span><span class="n">h</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">x</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">C</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">i</span><span class="o">,</span> <span class="bp">‖</span><span class="n">g</span> <span class="n">i</span> <span class="n">x</span><span class="bp">‖</span> <span class="bp">≤</span> <span class="n">C</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">C'</span><span class="o">,</span> <span class="bp">∀</span> <span class="n">i</span><span class="o">,</span> <span class="bp">‖</span><span class="n">g</span> <span class="n">i</span><span class="bp">‖</span> <span class="bp">≤</span> <span class="n">C'</span> <span class="o">:=</span> <span class="kd">by</span> <span class="c1">-- sequence of subsets consisting of those `x : E` with norms `‖g i x‖` bounded by `n`</span> <span class="k">let</span> <span class="n">e</span> <span class="o">:</span> <span class="n">ℕ</span> <span class="bp">→</span> <span class="n">Set</span> <span class="n">E</span> <span class="o">:=</span> <span class="k">fun</span> <span class="n">n</span> <span class="bp">=></span> <span class="bp">⋂</span> <span class="n">i</span> <span class="o">:</span> <span class="n">ι</span><span class="o">,</span> <span class="o">{</span> <span class="n">x</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">|</span> <span class="bp">‖</span><span class="n">g</span> <span class="n">i</span> <span class="n">x</span><span class="bp">‖</span> <span class="bp">≤</span> <span class="n">n</span> <span class="o">}</span> <span class="c1">-- each of these sets is closed</span> <span class="k">have</span> <span class="n">hc</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">,</span> <span class="n">IsClosed</span> <span class="o">(</span><span class="n">e</span> <span class="n">n</span><span class="o">)</span> <span class="gr">sorry</span> <span class="c1">-- the union is the entire space; this is where we use `h`</span> <span class="k">have</span> <span class="n">hU</span> <span class="o">:</span> <span class="o">(</span><span class="bp">⋃</span> <span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">,</span> <span class="n">e</span> <span class="n">n</span><span class="o">)</span> <span class="bp">=</span> <span class="n">univ</span> <span class="gr">sorry</span> <span class="c">/-</span><span class="cm"> apply the Baire category theorem to conclude that for some `m : ℕ`,</span> <span class="cm"> `e m` contains some `x` -/</span> <span class="n">obtain</span> <span class="o">⟨</span><span class="n">m</span><span class="o">,</span> <span class="n">x</span><span class="o">,</span> <span class="n">hx</span><span class="o">⟩</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">m</span><span class="o">,</span> <span class="bp">∃</span> <span class="n">x</span><span class="o">,</span> <span class="n">x</span> <span class="bp">∈</span> <span class="n">interior</span> <span class="o">(</span><span class="n">e</span> <span class="n">m</span><span class="o">)</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">obtain</span> <span class="o">⟨</span><span class="n">ε</span><span class="o">,</span> <span class="n">ε_pos</span><span class="o">,</span> <span class="n">hε</span><span class="o">⟩</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">ε</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="n">ball</span> <span class="n">x</span> <span class="n">ε</span> <span class="bp">⊆</span> <span class="n">interior</span> <span class="o">(</span><span class="n">e</span> <span class="n">m</span><span class="o">)</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">obtain</span> <span class="o">⟨</span><span class="n">k</span><span class="o">,</span> <span class="n">hk</span><span class="o">⟩</span> <span class="o">:</span> <span class="bp">∃</span> <span class="n">k</span> <span class="o">:</span> <span class="bp">𝕜</span><span class="o">,</span> <span class="mi">1</span> <span class="bp"><</span> <span class="bp">‖</span><span class="n">k</span><span class="bp">‖</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="c1">-- show all elements in the ball have norm bounded by `m` after applying any `g i`</span> <span class="k">have</span> <span class="n">real_norm_le</span> <span class="o">:</span> <span class="bp">∀</span> <span class="n">z</span> <span class="bp">∈</span> <span class="n">ball</span> <span class="n">x</span> <span class="n">ε</span><span class="o">,</span> <span class="bp">∀</span> <span class="o">(</span><span class="n">i</span> <span class="o">:</span> <span class="n">ι</span><span class="o">),</span> <span class="bp">‖</span><span class="n">g</span> <span class="n">i</span> <span class="n">z</span><span class="bp">‖</span> <span class="bp">≤</span> <span class="n">m</span> <span class="gr">sorry</span> <span class="k">have</span> <span class="n">εk_pos</span> <span class="o">:</span> <span class="mi">0</span> <span class="bp"><</span> <span class="n">ε</span> <span class="bp">/</span> <span class="bp">‖</span><span class="n">k</span><span class="bp">‖</span> <span class="o">:=</span> <span class="gr">sorry</span> <span class="n">refine'</span> <span class="o">⟨(</span><span class="n">m</span> <span class="bp">+</span> <span class="n">m</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="bp">/</span> <span class="o">(</span><span class="n">ε</span> <span class="bp">/</span> <span class="bp">‖</span><span class="n">k</span><span class="bp">‖</span><span class="o">),</span> <span class="k">fun</span> <span class="n">i</span> <span class="bp">=></span> <span class="n">ContinuousLinearMap.op_norm_le_of_shell</span> <span class="n">ε_pos</span> <span class="n">_</span> <span class="n">hk</span> <span class="n">_</span><span class="o">⟩</span> <span class="gr">sorry</span> <span class="gr">sorry</span> </pre></div> </div> </section> <section id="asymptotic-comparisons"> <h3><span class="section-number">9.2.3. </span>Asymptotic comparisons<a class="headerlink" href="#asymptotic-comparisons" title="Permalink to this heading"></a></h3> <p>Defining differentiability also requires asymptotic comparisons. Mathlib has an extensive library covering the big O and little o relations, whose definitions are shown below. Opening the <code class="docutils literal notranslate"><span class="pre">asymptotics</span></code> locale allows us to use the corresponding notation. Here we will only use little o to define differentiability.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">open</span> <span class="n">Asymptotics</span> <span class="kn">open</span> <span class="n">Asymptotics</span> <span class="kd">example</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">{</span><span class="n">E</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NormedGroup</span> <span class="n">E</span><span class="o">]</span> <span class="o">{</span><span class="n">F</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NormedGroup</span> <span class="n">F</span><span class="o">]</span> <span class="o">(</span><span class="n">c</span> <span class="o">:</span> <span class="n">ℝ</span><span class="o">)</span> <span class="o">(</span><span class="n">l</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">α</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">E</span><span class="o">)</span> <span class="o">(</span><span class="n">g</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">F</span><span class="o">)</span> <span class="o">:</span> <span class="n">IsBigOWith</span> <span class="n">c</span> <span class="n">l</span> <span class="n">f</span> <span class="n">g</span> <span class="bp">↔</span> <span class="bp">∀ᶠ</span> <span class="n">x</span> <span class="k">in</span> <span class="n">l</span><span class="o">,</span> <span class="bp">‖</span><span class="n">f</span> <span class="n">x</span><span class="bp">‖</span> <span class="bp">≤</span> <span class="n">c</span> <span class="bp">*</span> <span class="bp">‖</span><span class="n">g</span> <span class="n">x</span><span class="bp">‖</span> <span class="o">:=</span> <span class="n">isBigOWith_iff</span> <span class="kd">example</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">{</span><span class="n">E</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NormedGroup</span> <span class="n">E</span><span class="o">]</span> <span class="o">{</span><span class="n">F</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NormedGroup</span> <span class="n">F</span><span class="o">]</span> <span class="o">(</span><span class="n">l</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">α</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">E</span><span class="o">)</span> <span class="o">(</span><span class="n">g</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">F</span><span class="o">)</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">=</span><span class="n">O</span><span class="o">[</span><span class="n">l</span><span class="o">]</span> <span class="n">g</span> <span class="bp">↔</span> <span class="bp">∃</span> <span class="n">C</span><span class="o">,</span> <span class="n">IsBigOWith</span> <span class="n">C</span> <span class="n">l</span> <span class="n">f</span> <span class="n">g</span> <span class="o">:=</span> <span class="n">isBigO_iff_isBigOWith</span> <span class="kd">example</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">{</span><span class="n">E</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NormedGroup</span> <span class="n">E</span><span class="o">]</span> <span class="o">{</span><span class="n">F</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NormedGroup</span> <span class="n">F</span><span class="o">]</span> <span class="o">(</span><span class="n">l</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">α</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">E</span><span class="o">)</span> <span class="o">(</span><span class="n">g</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">F</span><span class="o">)</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">=</span><span class="n">o</span><span class="o">[</span><span class="n">l</span><span class="o">]</span> <span class="n">g</span> <span class="bp">↔</span> <span class="bp">∀</span> <span class="n">C</span> <span class="bp">></span> <span class="mi">0</span><span class="o">,</span> <span class="n">IsBigOWith</span> <span class="n">C</span> <span class="n">l</span> <span class="n">f</span> <span class="n">g</span> <span class="o">:=</span> <span class="n">isLittleO_iff_forall_isBigOWith</span> <span class="kd">example</span> <span class="o">{</span><span class="n">α</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">{</span><span class="n">E</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NormedAddCommGroup</span> <span class="n">E</span><span class="o">]</span> <span class="o">(</span><span class="n">l</span> <span class="o">:</span> <span class="n">Filter</span> <span class="n">α</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="n">g</span> <span class="o">:</span> <span class="n">α</span> <span class="bp">→</span> <span class="n">E</span><span class="o">)</span> <span class="o">:</span> <span class="n">f</span> <span class="bp">~</span><span class="o">[</span><span class="n">l</span><span class="o">]</span> <span class="n">g</span> <span class="bp">↔</span> <span class="o">(</span><span class="n">f</span> <span class="bp">-</span> <span class="n">g</span><span class="o">)</span> <span class="bp">=</span><span class="n">o</span><span class="o">[</span><span class="n">l</span><span class="o">]</span> <span class="n">g</span> <span class="o">:=</span> <span class="n">Iff.rfl</span> </pre></div> </div> </section> <section id="differentiability"> <h3><span class="section-number">9.2.4. </span>Differentiability<a class="headerlink" href="#differentiability" title="Permalink to this heading"></a></h3> <p>We are now ready to discuss differentiable functions between normed spaces. In analogy the elementary one-dimensional, mathlib defines a predicate <code class="docutils literal notranslate"><span class="pre">has_fderiv_at</span></code> and a function <code class="docutils literal notranslate"><span class="pre">fderiv</span></code>. Here the letter “f” stands for <em>Fréchet</em>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">variable</span> <span class="o">{</span><span class="bp">𝕜</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NontriviallyNormedField</span> <span class="bp">𝕜</span><span class="o">]</span> <span class="o">{</span><span class="n">E</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NormedAddCommGroup</span> <span class="n">E</span><span class="o">]</span> <span class="o">[</span><span class="n">NormedSpace</span> <span class="bp">𝕜</span> <span class="n">E</span><span class="o">]</span> <span class="o">{</span><span class="n">F</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NormedAddCommGroup</span> <span class="n">F</span><span class="o">]</span> <span class="o">[</span><span class="n">NormedSpace</span> <span class="bp">𝕜</span> <span class="n">F</span><span class="o">]</span> <span class="kd">example</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span> <span class="n">F</span><span class="o">)</span> <span class="o">(</span><span class="n">f'</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">F</span><span class="o">)</span> <span class="o">(</span><span class="n">x₀</span> <span class="o">:</span> <span class="n">E</span><span class="o">)</span> <span class="o">:</span> <span class="n">HasFDerivAt</span> <span class="n">f</span> <span class="n">f'</span> <span class="n">x₀</span> <span class="bp">↔</span> <span class="o">(</span><span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">f</span> <span class="n">x</span> <span class="bp">-</span> <span class="n">f</span> <span class="n">x₀</span> <span class="bp">-</span> <span class="n">f'</span> <span class="o">(</span><span class="n">x</span> <span class="bp">-</span> <span class="n">x₀</span><span class="o">))</span> <span class="bp">=</span><span class="n">o</span><span class="o">[</span><span class="bp">𝓝</span> <span class="n">x₀</span><span class="o">]</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">x</span> <span class="bp">-</span> <span class="n">x₀</span> <span class="o">:=</span> <span class="n">Iff.rfl</span> <span class="kd">example</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span> <span class="n">F</span><span class="o">)</span> <span class="o">(</span><span class="n">f'</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">F</span><span class="o">)</span> <span class="o">(</span><span class="n">x₀</span> <span class="o">:</span> <span class="n">E</span><span class="o">)</span> <span class="o">(</span><span class="n">hff'</span> <span class="o">:</span> <span class="n">HasFDerivAt</span> <span class="n">f</span> <span class="n">f'</span> <span class="n">x₀</span><span class="o">)</span> <span class="o">:</span> <span class="n">fderiv</span> <span class="bp">𝕜</span> <span class="n">f</span> <span class="n">x₀</span> <span class="bp">=</span> <span class="n">f'</span> <span class="o">:=</span> <span class="n">hff'.fderiv</span> </pre></div> </div> <p>We also have iterated derivatives that take values in the type of multilinear maps <code class="docutils literal notranslate"><span class="pre">E</span> <span class="pre">[×n]→L[𝕜]</span> <span class="pre">F</span></code>, and we have continuously differential functions. The type <code class="docutils literal notranslate"><span class="pre">with_top</span> <span class="pre">ℕ</span></code> is <code class="docutils literal notranslate"><span class="pre">ℕ</span></code> with an additional element <code class="docutils literal notranslate"><span class="pre">⊤</span></code> that is bigger than every natural number. So <span class="math notranslate nohighlight">\(\mathcal{C}^\infty\)</span> functions are functions <code class="docutils literal notranslate"><span class="pre">f</span></code> that satisfy <code class="docutils literal notranslate"><span class="pre">cont_diff</span> <span class="pre">𝕜</span> <span class="pre">⊤</span> <span class="pre">f</span></code>.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span> <span class="n">F</span><span class="o">)</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span> <span class="n">E</span><span class="o">[</span><span class="bp">×</span><span class="n">n</span><span class="o">]</span><span class="bp">→</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">F</span> <span class="o">:=</span> <span class="n">iteratedFDeriv</span> <span class="bp">𝕜</span> <span class="n">n</span> <span class="n">f</span> <span class="kd">example</span> <span class="o">(</span><span class="n">n</span> <span class="o">:</span> <span class="n">WithTop</span> <span class="n">ℕ</span><span class="o">)</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span> <span class="n">F</span><span class="o">}</span> <span class="o">:</span> <span class="n">ContDiff</span> <span class="bp">𝕜</span> <span class="n">n</span> <span class="n">f</span> <span class="bp">↔</span> <span class="o">(</span><span class="bp">∀</span> <span class="n">m</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">,</span> <span class="o">(</span><span class="n">m</span> <span class="o">:</span> <span class="n">WithTop</span> <span class="n">ℕ</span><span class="o">)</span> <span class="bp">≤</span> <span class="n">n</span> <span class="bp">→</span> <span class="n">Continuous</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">iteratedFDeriv</span> <span class="bp">𝕜</span> <span class="n">m</span> <span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="bp">∧</span> <span class="bp">∀</span> <span class="n">m</span> <span class="o">:</span> <span class="n">ℕ</span><span class="o">,</span> <span class="o">(</span><span class="n">m</span> <span class="o">:</span> <span class="n">WithTop</span> <span class="n">ℕ</span><span class="o">)</span> <span class="bp"><</span> <span class="n">n</span> <span class="bp">→</span> <span class="n">Differentiable</span> <span class="bp">𝕜</span> <span class="k">fun</span> <span class="n">x</span> <span class="bp">=></span> <span class="n">iteratedFDeriv</span> <span class="bp">𝕜</span> <span class="n">m</span> <span class="n">f</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">contDiff_iff_continuous_differentiable</span> </pre></div> </div> <p>There is a stricter notion of differentiability called <code class="docutils literal notranslate"><span class="pre">has_strict_fderiv_at</span></code>, which is used in the statement of the inverse function theorem and the statement of the implicit function theorem, both of which are in mathlib. Over <code class="docutils literal notranslate"><span class="pre">ℝ</span></code> or <code class="docutils literal notranslate"><span class="pre">ℂ</span></code>, continuously differentiable functions are strictly differentiable.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kd">example</span> <span class="o">{</span><span class="bp">𝕂</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">IsROrC</span> <span class="bp">𝕂</span><span class="o">]</span> <span class="o">{</span><span class="n">E</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NormedAddCommGroup</span> <span class="n">E</span><span class="o">]</span> <span class="o">[</span><span class="n">NormedSpace</span> <span class="bp">𝕂</span> <span class="n">E</span><span class="o">]</span> <span class="o">{</span><span class="n">F</span> <span class="o">:</span> <span class="kt">Type</span> <span class="n">_</span><span class="o">}</span> <span class="o">[</span><span class="n">NormedAddCommGroup</span> <span class="n">F</span><span class="o">]</span> <span class="o">[</span><span class="n">NormedSpace</span> <span class="bp">𝕂</span> <span class="n">F</span><span class="o">]</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span> <span class="n">F</span><span class="o">}</span> <span class="o">{</span><span class="n">x</span> <span class="o">:</span> <span class="n">E</span><span class="o">}</span> <span class="o">{</span><span class="n">n</span> <span class="o">:</span> <span class="n">WithTop</span> <span class="n">ℕ</span><span class="o">}</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">ContDiffAt</span> <span class="bp">𝕂</span> <span class="n">n</span> <span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="o">(</span><span class="n">hn</span> <span class="o">:</span> <span class="mi">1</span> <span class="bp">≤</span> <span class="n">n</span><span class="o">)</span> <span class="o">:</span> <span class="n">HasStrictFDerivAt</span> <span class="n">f</span> <span class="o">(</span><span class="n">fderiv</span> <span class="bp">𝕂</span> <span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">hf.hasStrictFDerivAt</span> <span class="n">hn</span> </pre></div> </div> <p>The local inverse theorem is stated using an operation that produces an inverse function from a function and the assumptions that the function is strictly differentiable at a point <code class="docutils literal notranslate"><span class="pre">a</span></code> and that its derivative is an isomorphism.</p> <p>The first example below gets this local inverse. The next one states that it is indeed a local inverse from the left and from the right, and that it is strictly differentiable.</p> <div class="highlight-lean notranslate"><div class="highlight"><pre><span></span><span class="kn">section</span> <span class="n">LocalInverse</span> <span class="kd">variable</span> <span class="o">[</span><span class="n">CompleteSpace</span> <span class="n">E</span><span class="o">]</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span> <span class="n">F</span><span class="o">}</span> <span class="o">{</span><span class="n">f'</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">≃</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">F</span><span class="o">}</span> <span class="o">{</span><span class="n">a</span> <span class="o">:</span> <span class="n">E</span><span class="o">}</span> <span class="kd">example</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">HasStrictFDerivAt</span> <span class="n">f</span> <span class="o">(</span><span class="n">f'</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">F</span><span class="o">)</span> <span class="n">a</span><span class="o">)</span> <span class="o">:</span> <span class="n">F</span> <span class="bp">→</span> <span class="n">E</span> <span class="o">:=</span> <span class="n">HasStrictFDerivAt.localInverse</span> <span class="n">f</span> <span class="n">f'</span> <span class="n">a</span> <span class="n">hf</span> <span class="kd">example</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">HasStrictFDerivAt</span> <span class="n">f</span> <span class="o">(</span><span class="n">f'</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">F</span><span class="o">)</span> <span class="n">a</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">x</span> <span class="k">in</span> <span class="bp">𝓝</span> <span class="n">a</span><span class="o">,</span> <span class="n">hf.localInverse</span> <span class="n">f</span> <span class="n">f'</span> <span class="n">a</span> <span class="o">(</span><span class="n">f</span> <span class="n">x</span><span class="o">)</span> <span class="bp">=</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">hf.eventually_left_inverse</span> <span class="kd">example</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">HasStrictFDerivAt</span> <span class="n">f</span> <span class="o">(</span><span class="n">f'</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">F</span><span class="o">)</span> <span class="n">a</span><span class="o">)</span> <span class="o">:</span> <span class="bp">∀ᶠ</span> <span class="n">x</span> <span class="k">in</span> <span class="bp">𝓝</span> <span class="o">(</span><span class="n">f</span> <span class="n">a</span><span class="o">),</span> <span class="n">f</span> <span class="o">(</span><span class="n">hf.localInverse</span> <span class="n">f</span> <span class="n">f'</span> <span class="n">a</span> <span class="n">x</span><span class="o">)</span> <span class="bp">=</span> <span class="n">x</span> <span class="o">:=</span> <span class="n">hf.eventually_right_inverse</span> <span class="kd">example</span> <span class="o">[</span><span class="n">CompleteSpace</span> <span class="n">E</span><span class="o">]</span> <span class="o">{</span><span class="n">f</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span> <span class="n">F</span><span class="o">}</span> <span class="o">{</span><span class="n">f'</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">≃</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">F</span><span class="o">}</span> <span class="o">{</span><span class="n">a</span> <span class="o">:</span> <span class="n">E</span><span class="o">}</span> <span class="o">(</span><span class="n">hf</span> <span class="o">:</span> <span class="n">HasStrictFDerivAt</span> <span class="n">f</span> <span class="o">(</span><span class="n">f'</span> <span class="o">:</span> <span class="n">E</span> <span class="bp">→</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">F</span><span class="o">)</span> <span class="n">a</span><span class="o">)</span> <span class="o">:</span> <span class="n">HasStrictFDerivAt</span> <span class="o">(</span><span class="n">HasStrictFDerivAt.localInverse</span> <span class="n">f</span> <span class="n">f'</span> <span class="n">a</span> <span class="n">hf</span><span class="o">)</span> <span class="o">(</span><span class="n">f'.symm</span> <span class="o">:</span> <span class="n">F</span> <span class="bp">→</span><span class="n">L</span><span class="o">[</span><span class="bp">𝕜</span><span class="o">]</span> <span class="n">E</span><span class="o">)</span> <span class="o">(</span><span class="n">f</span> <span class="n">a</span><span class="o">)</span> <span class="o">:=</span> <span class="n">HasStrictFDerivAt.to_localInverse</span> <span class="n">hf</span> <span class="kd">end</span> <span class="n">LocalInverse</span> </pre></div> </div> <p>This has been only a quick tour of the differential calculus in mathlib. The library contains many variations that we have not discussed. For example, you may want to use one-sided derivatives in the one-dimensional setting. The means to do so are found in mathlib in a more general context; see <code class="docutils literal notranslate"><span class="pre">HasFDerivWithinAt</span></code> or the even more general <code class="docutils literal notranslate"><span class="pre">HasFDerivAtFilter</span></code>.</p> </section> </section> </section> </div> </div> <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> <a href="C08_Topology.html" class="btn btn-neutral float-left" title="8. Topology" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> <a href="genindex.html" class="btn btn-neutral float-right" title="Index" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> </div> <hr/> <div role="contentinfo"> <p>© Copyright 2020, Jeremy Avigad, Kevin Buzzard, Robert Y. Lewis, Patrick Massot.</p> </div> Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. </footer> </div> </div> </section> </div> <script> jQuery(function () { SphinxRtdTheme.Navigation.enable(true); }); </script> </body> </html>
-
-
-
@@ -0,0 +1,116 @@<!DOCTYPE html> <html class="writer-html5" lang="en" > <head> <meta charset="utf-8" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Integration and Measure Theory — Mathematics in Lean 0.1 documentation</title> <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> <link rel="stylesheet" href="_static/css/custom.css" type="text/css" /> <link rel="shortcut icon" href="_static/favicon.ico"/> <!--[if lt IE 9]> <script src="_static/js/html5shiv.min.js"></script> <![endif]--> <script src="_static/jquery.js"></script> <script src="_static/_sphinx_javascript_frameworks_compat.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script src="_static/doctools.js"></script> <script src="_static/sphinx_highlight.js"></script> <script src="_static/js/theme.js"></script> <link rel="index" title="Index" href="genindex.html" /> <link rel="search" title="Search" href="search.html" /> </head> <body class="wy-body-for-nav"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search" > <a href="index.html" class="icon icon-home"> Mathematics in Lean </a> <div role="search"> <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> <ul> <li class="toctree-l1"><a class="reference internal" href="C01_Introduction.html">1. Introduction</a></li> <li class="toctree-l1"><a class="reference internal" href="C02_Basics.html">2. Basics</a></li> <li class="toctree-l1"><a class="reference internal" href="C03_Logic.html">3. Logic</a></li> <li class="toctree-l1"><a class="reference internal" href="C04_Sets_and_Functions.html">4. Sets and Functions</a></li> <li class="toctree-l1"><a class="reference internal" href="C05_Number_Theory.html">5. Number Theory</a></li> <li class="toctree-l1"><a class="reference internal" href="C06_Structures.html">6. Structures</a></li> <li class="toctree-l1"><a class="reference internal" href="C07_Hierarchies.html">7. Hierarchies</a></li> <li class="toctree-l1"><a class="reference internal" href="C08_Topology.html">8. Topology</a></li> <li class="toctree-l1"><a class="reference internal" href="C09_Differential_Calculus.html">9. Differential Calculus</a></li> </ul> <ul> <li class="toctree-l1"><a class="reference internal" href="genindex.html">Index</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="index.html">Mathematics in Lean</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="Page navigation"> <ul class="wy-breadcrumbs"> <li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li> <li class="breadcrumb-item active">Integration and Measure Theory</li> <li class="wy-breadcrumbs-aside"> <a href="_sources/C10_Integration_and_Measure_Theory.rst.txt" rel="nofollow"> View page source</a> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <span class="target" id="integration-and-measure-theory"></span><section id="index-0"> <span id="id1"></span><h1>Integration and Measure Theory<a class="headerlink" href="#index-0" title="Permalink to this heading"></a></h1> </section> </div> </div> <footer> <hr/> <div role="contentinfo"> <p>© Copyright 2020, Jeremy Avigad, Kevin Buzzard, Robert Y. Lewis, Patrick Massot.</p> </div> Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. </footer> </div> </div> </section> </div> <script> jQuery(function () { SphinxRtdTheme.Navigation.enable(true); }); </script> </body> </html>
-
-
-
-
-
-
@@ -0,0 +1,7 @@.. _introduction: Introduction ============ .. include:: C01_Introduction/S01_Getting_Started.inc .. include:: C01_Introduction/S02_Overview.inc
-
-
-
@@ -0,0 +1,19 @@.. _basics: Basics ====== This chapter is designed to introduce you to the nuts and bolts of mathematical reasoning in Lean: calculating, applying lemmas and theorems, and reasoning about generic structures. .. include:: C02_Basics/S01_Calculating.inc .. include:: C02_Basics/S02_Proving_Identities_in_Algebraic_Structures.inc .. include:: C02_Basics/S03_Using_Theorems_and_Lemmas.inc .. include:: C02_Basics/S04_More_on_Order_and_Divisibility.inc .. include:: C02_Basics/S05_Proving_Facts_about_Algebraic_Structures.inc
-
-
-
@@ -0,0 +1,37 @@.. _logic: Logic ===== In the last chapter, we dealt with equations, inequalities, and basic mathematical statements like ":math:`x` divides :math:`y`." Complex mathematical statements are built up from simple ones like these using logical terms like "and," "or," "not," and "if ... then," "every," and "some." In this chapter, we show you how to work with statements that are built up in this way. .. include:: C03_Logic/S01_Implication_and_the_Universal_Quantifier.inc .. include:: C03_Logic/S02_The_Existential_Quantifier.inc .. include:: C03_Logic/S03_Negation.inc .. include:: C03_Logic/S04_Conjunction_and_Bi-implication.inc .. include:: C03_Logic/S05_Disjunction.inc .. include:: C03_Logic/S06_Sequences_and_Convergence.inc
-
-
-
@@ -0,0 +1,45 @@.. _sets_and_functions: Sets and Functions ================== The vocabulary of sets, relations, and functions provides a uniform language for carrying out constructions in all the branches of mathematics. Since functions and relations can be defined in terms of sets, axiomatic set theory can be used as a foundation for mathematics. Lean's foundation is based instead on the primitive notion of a *type*, and it includes ways of defining functions between types. Every expression in Lean has a type: there are natural numbers, real numbers, functions from reals to reals, groups, vector spaces, and so on. Some expressions *are* types, which is to say, their type is ``Type``. Lean and mathlib provide ways of defining new types, and ways of defining objects of those types. Conceptually, you can think of a type as just a set of objects. Requiring every object to have a type has some advantages. For example, it makes it possible to overload notation like ``+``, and it sometimes makes input less verbose because Lean can infer a lot of information from an object's type. The type system also enables Lean to flag errors when you apply a function to the wrong number of arguments, or apply a function to arguments of the wrong type. Lean's library does define elementary set-theoretic notions. In contrast to set theory, in Lean a set is always a set of objects of some type, such as a set natural numbers or a set of functions from real numbers to real numbers. The distinction between types and set takes some getting used to, but this chapter will take you through the essentials. .. include:: C04_Sets_and_Functions/S01_Sets.inc .. include:: C04_Sets_and_Functions/S02_Functions.inc .. include:: C04_Sets_and_Functions/S03_The_Schroeder_Bernstein_Theorem.inc
-
-
-
@@ -0,0 +1,14 @@.. _number_theory: Number Theory ============= In this chapter, we show you how to formalize some elementary results in number theory. As we deal with more substantive mathematical content, the proofs will get longer and more involved, building on the skills you have already mastered. .. include:: C05_Number_Theory/S01_Irrational_Roots.inc .. include:: C05_Number_Theory/S02_Induction_and_Recursion.inc .. include:: C05_Number_Theory/S03_Infinitely_Many_Primes.inc
-
-
-
@@ -0,0 +1,29 @@.. _structures: Structures ========== Modern mathematics makes essential use of algebraic structures, which encapsulate patterns that can be instantiated in multiple settings. The subject provides various ways of defining such structures and constructing particular instances. Lean therefore provides corresponding ways of defining structures formally and working with them. You have already seen examples of algebraic structures in Lean, such as rings and lattices, which were discussed in :numref:`Chapter %s <basics>`. This chapter will explain the mysterious square bracket annotations that you saw there, ``[Ring α]`` and ``[Lattice α]``. It will also show you how to define and use algebraic structures on your own. For more technical detail, you can consult `Theorem Proving in Lean <https://leanprover.github.io/theorem_proving_in_lean/>`_, and a paper by Anne Baanen, `Use and abuse of instance parameters in the Lean mathematical library <https://arxiv.org/abs/2202.01629>`_. .. include:: C06_Structures/S01_Structures.inc .. include:: C06_Structures/S02_Algebraic_Structures.inc .. include:: C06_Structures/S03_Building_the_Gaussian_Integers.inc
-
-
-
@@ -0,0 +1,26 @@.. _hierarchies: Hierarchies =========== We have seen in :numref:`Chapter %s <structures>` how to define the class of groups and build instances of this class, and then how to build an instance of the commutative ring class. But of course there is a hierarchy here: a commutative ring is in particular an additive group. In this chapter we will study how to build such hierarchies. They appear in all branches of mathematics but in this chapter the emphasis will be on algebraic examples. It may seem premature to discuss how to build hierarchies before more discussions about using existing hierarchies. But some understanding of the technology underlying hierarchies is required to use them. So you should probably still read this chapter, but without trying too hard to remember everything on your first read, then read the following chapters and come back here for a second reading. In this chapter, we will redefine (simpler versions of) many things that appear in Mathlib so we will used indices to distinguish our version. For instance we will have ``Ring₁`` as our version of ``Ring``. Since we will gradually explain more powerful ways of formalizing structures, those indices will sometimes grow beyond one. .. include:: C07_Hierarchies/S01_Basics.inc .. include:: C07_Hierarchies/S02_Morphisms.inc .. include:: C07_Hierarchies/S03_Subobjects.inc
-
-
-
@@ -0,0 +1,84 @@.. _topology: .. index:: topology Topology ======== Calculus is based on the concept of a function, which is used to model quantities that depend on one another. For example, it is common to study quantities that change over time. The notion of a *limit* is also fundamental. We may say that the limit of a function :math:`f(x)` is a value :math:`b` as :math:`x` approaches a value :math:`a`, or that :math:`f(x)` *converges to* :math:`b` as :math:`x` approaches :math:`a`. Equivalently, we may say that a :math:`f(x)` approaches :math:`a` as :math:`x` approaches a value :math:`b`, or that it *tends to* :math:`b` as :math:`x` tends to :math:`a`. We have already begun to consider such notions in :numref:`sequences_and_convergence`. *Topology* is the abstract study of limits and continuity. Having covered the essentials of formalization in Chapters :numref:`%s <basics>` to :numref:`%s <structures>`, in this chapter, we will explain how topological notions are formalized in mathlib. Not only do topological abstractions apply in much greater generality, but that also, somewhat paradoxically, make it easier to reason about limits and continuity in concrete instances. Topological notions build on quite a few layers of mathematical structure. The first layer is naive set theory, as described in :numref:`Chapter %s <sets_and_functions>`. The next layer is the theory of *filters*, which we will describe in :numref:`filters`. On top of that, we layer the theories of *topological spaces*, *metric spaces*, and a slightly more exotic intermediate notion called a *uniform space*. Whereas previous chapters relied on mathematical notions that were likely familiar to you, the notion of a filter less well known, even to many working mathematicians. The notion is essential, however, for formalizing mathematics effectively. Let us explain why. Let ``f : ℝ → ℝ`` be any function. We can consider the limit of ``f x`` as ``x`` approaches some value ``x₀``, but we can also consider the limit of ``f x`` as ``x`` approaches infinity or negative infinity. We can moreover consider the limit of ``f x`` as ``x`` approaches ``x₀`` from the right, conventionally written ``x₀⁺``, or from the left, written ``x₀⁻``. There are variations where ``x`` approaches ``x₀`` or ``x₀⁺`` or ``x₀⁻`` but is not allowed to take on the value ``x₀`` itself. This results in at least eight ways that ``x`` can approach something. We can also restrict to rational values of ``x`` or place other constraints on the domain, but let's stick to those 8 cases. We have a similar variety of options on the codomain: we can specify that ``f x`` approaches a value from the left or right, or that it approaches positive or negative infinity, and so on. For example, we may wish to say that ``f x`` tends to ``+∞`` when ``x`` tends to ``x₀`` from the right without being equal to ``x₀``. This results in 64 different kinds of limit statements, and we haven't even begun to deal with limits of sequences, as we did in :numref:`sequences_and_convergence`. The problem is compounded even further when it comes to the supporting lemmas. For instance, limits compose: if ``f x`` tends to ``y₀`` when ``x`` tends to ``x₀`` and ``g y`` tends to ``z₀`` when ``y`` tends to ``y₀`` then ``g ∘ f x`` tends to ``z₀`` when ``x`` tends to ``x₀``. There are three notions of "tends to" at play here, each of which can be instantiated in any of the eight ways described in the previous paragraph. This results in 512 lemmas, a lot to have to add to a library! Informally, mathematicians generally prove two or three of these and simply note that the rest can be proved "in the same way." Formalizing mathematics requires making the relevant notion of "sameness" fully explicit, and that is exactly what Bourbaki's theory of filters manages to do. .. include:: C08_Topology/S01_Filters.inc .. include:: C08_Topology/S02_Metric_Spaces.inc .. include:: C08_Topology/S03_Topological_Spaces.inc
-
-
-
@@ -0,0 +1,18 @@.. _differential_calculus: .. index:: differential calculus Differential Calculus ===================== We now consider the formalization of notions from *analysis*, starting with differentiation in this chapter and turning integration and measure theory in the next. In :numref:`elementary_differential_calculus`, we stick with the setting of functions from the real numbers to the real numbers, which is familiar from any introductory calculus class. In :numref:`normed_spaces`, we then consider the notion of a derivative in a much broader setting. .. include:: C09_Differential_Calculus/S01_Elementary_Differential_Calculus.inc .. include:: C09_Differential_Calculus/S02_Differential_Calculus_in_Normed_Spaces.inc
-
-
-
@@ -0,0 +1,11 @@.. _integration_and_measure_theory: .. index:: integration Integration and Measure Theory ============================== .. .. include:: C09_Integration_and_Measure_Theory/S01_Elementary_Integration.inc .. include:: C09_Integration_and_Measure_Theory/S02_Measure_Theory.inc .. include:: C09_Integration_and_Measure_Theory/S03_Integration.inc
-
-
-
@@ -0,0 +1,2 @@Index =====
-
-
-
@@ -0,0 +1,23 @@Mathematics in Lean =================== .. toctree:: :numbered: :maxdepth: 2 C01_Introduction C02_Basics C03_Logic C04_Sets_and_Functions C05_Number_Theory C06_Structures C07_Hierarchies C08_Topology C09_Differential_Calculus .. toctree:: :hidden: genindex
-
-
-
@@ -0,0 +1,123 @@/* Compatability shim for jQuery and underscores.js. * * Copyright Sphinx contributors * Released under the two clause BSD licence */ /** * small helper function to urldecode strings * * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL */ jQuery.urldecode = function(x) { if (!x) { return x } return decodeURIComponent(x.replace(/\+/g, ' ')); }; /** * small helper function to urlencode strings */ jQuery.urlencode = encodeURIComponent; /** * This function returns the parsed url parameters of the * current request. Multiple values per key are supported, * it will always return arrays of strings for the value parts. */ jQuery.getQueryParameters = function(s) { if (typeof s === 'undefined') s = document.location.search; var parts = s.substr(s.indexOf('?') + 1).split('&'); var result = {}; for (var i = 0; i < parts.length; i++) { var tmp = parts[i].split('=', 2); var key = jQuery.urldecode(tmp[0]); var value = jQuery.urldecode(tmp[1]); if (key in result) result[key].push(value); else result[key] = [value]; } return result; }; /** * highlight a given string on a jquery object by wrapping it in * span elements with the given class name. */ jQuery.fn.highlightText = function(text, className) { function highlight(node, addItems) { if (node.nodeType === 3) { var val = node.nodeValue; var pos = val.toLowerCase().indexOf(text); if (pos >= 0 && !jQuery(node.parentNode).hasClass(className) && !jQuery(node.parentNode).hasClass("nohighlight")) { var span; var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); if (isInSVG) { span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); } else { span = document.createElement("span"); span.className = className; } span.appendChild(document.createTextNode(val.substr(pos, text.length))); node.parentNode.insertBefore(span, node.parentNode.insertBefore( document.createTextNode(val.substr(pos + text.length)), node.nextSibling)); node.nodeValue = val.substr(0, pos); if (isInSVG) { var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); var bbox = node.parentElement.getBBox(); rect.x.baseVal.value = bbox.x; rect.y.baseVal.value = bbox.y; rect.width.baseVal.value = bbox.width; rect.height.baseVal.value = bbox.height; rect.setAttribute('class', className); addItems.push({ "parent": node.parentNode, "target": rect}); } } } else if (!jQuery(node).is("button, select, textarea")) { jQuery.each(node.childNodes, function() { highlight(this, addItems); }); } } var addItems = []; var result = this.each(function() { highlight(this, addItems); }); for (var i = 0; i < addItems.length; ++i) { jQuery(addItems[i].parent).before(addItems[i].target); } return result; }; /* * backward compatibility for jQuery.browser * This will be supported until firefox bug is fixed. */ if (!jQuery.browser) { jQuery.uaMatch = function(ua) { ua = ua.toLowerCase(); var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || /(webkit)[ \/]([\w.]+)/.exec(ua) || /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || /(msie) ([\w.]+)/.exec(ua) || ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || []; return { browser: match[ 1 ] || "", version: match[ 2 ] || "0" }; }; jQuery.browser = {}; jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; }
-
-
html/_static/basic.css (new)
-
@@ -0,0 +1,903 @@/* * basic.css * ~~~~~~~~~ * * Sphinx stylesheet -- basic theme. * * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ /* -- main layout ----------------------------------------------------------- */ div.clearer { clear: both; } div.section::after { display: block; content: ''; clear: left; } /* -- relbar ---------------------------------------------------------------- */ div.related { width: 100%; font-size: 90%; } div.related h3 { display: none; } div.related ul { margin: 0; padding: 0 0 0 10px; list-style: none; } div.related li { display: inline; } div.related li.right { float: right; margin-right: 5px; } /* -- sidebar --------------------------------------------------------------- */ div.sphinxsidebarwrapper { padding: 10px 5px 0 10px; } div.sphinxsidebar { float: left; width: 230px; margin-left: -100%; font-size: 90%; word-wrap: break-word; overflow-wrap : break-word; } div.sphinxsidebar ul { list-style: none; } div.sphinxsidebar ul ul, div.sphinxsidebar ul.want-points { margin-left: 20px; list-style: square; } div.sphinxsidebar ul ul { margin-top: 0; margin-bottom: 0; } div.sphinxsidebar form { margin-top: 10px; } div.sphinxsidebar input { border: 1px solid #98dbcc; font-family: sans-serif; font-size: 1em; } div.sphinxsidebar #searchbox form.search { overflow: hidden; } div.sphinxsidebar #searchbox input[type="text"] { float: left; width: 80%; padding: 0.25em; box-sizing: border-box; } div.sphinxsidebar #searchbox input[type="submit"] { float: left; width: 20%; border-left: none; padding: 0.25em; box-sizing: border-box; } img { border: 0; max-width: 100%; } /* -- search page ----------------------------------------------------------- */ ul.search { margin: 10px 0 0 20px; padding: 0; } ul.search li { padding: 5px 0 5px 20px; background-image: url(file.png); background-repeat: no-repeat; background-position: 0 7px; } ul.search li a { font-weight: bold; } ul.search li p.context { color: #888; margin: 2px 0 0 30px; text-align: left; } ul.keywordmatches li.goodmatch a { font-weight: bold; } /* -- index page ------------------------------------------------------------ */ table.contentstable { width: 90%; margin-left: auto; margin-right: auto; } table.contentstable p.biglink { line-height: 150%; } a.biglink { font-size: 1.3em; } span.linkdescr { font-style: italic; padding-top: 5px; font-size: 90%; } /* -- general index --------------------------------------------------------- */ table.indextable { width: 100%; } table.indextable td { text-align: left; vertical-align: top; } table.indextable ul { margin-top: 0; margin-bottom: 0; list-style-type: none; } table.indextable > tbody > tr > td > ul { padding-left: 0em; } table.indextable tr.pcap { height: 10px; } table.indextable tr.cap { margin-top: 10px; background-color: #f2f2f2; } img.toggler { margin-right: 3px; margin-top: 3px; cursor: pointer; } div.modindex-jumpbox { border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; margin: 1em 0 1em 0; padding: 0.4em; } div.genindex-jumpbox { border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; margin: 1em 0 1em 0; padding: 0.4em; } /* -- domain module index --------------------------------------------------- */ table.modindextable td { padding: 2px; border-collapse: collapse; } /* -- general body styles --------------------------------------------------- */ div.body { min-width: 360px; max-width: 800px; } div.body p, div.body dd, div.body li, div.body blockquote { -moz-hyphens: auto; -ms-hyphens: auto; -webkit-hyphens: auto; hyphens: auto; } a.headerlink { visibility: hidden; } h1:hover > a.headerlink, h2:hover > a.headerlink, h3:hover > a.headerlink, h4:hover > a.headerlink, h5:hover > a.headerlink, h6:hover > a.headerlink, dt:hover > a.headerlink, caption:hover > a.headerlink, p.caption:hover > a.headerlink, div.code-block-caption:hover > a.headerlink { visibility: visible; } div.body p.caption { text-align: inherit; } div.body td { text-align: left; } .first { margin-top: 0 !important; } p.rubric { margin-top: 30px; font-weight: bold; } img.align-left, figure.align-left, .figure.align-left, object.align-left { clear: left; float: left; margin-right: 1em; } img.align-right, figure.align-right, .figure.align-right, object.align-right { clear: right; float: right; margin-left: 1em; } img.align-center, figure.align-center, .figure.align-center, object.align-center { display: block; margin-left: auto; margin-right: auto; } img.align-default, figure.align-default, .figure.align-default { display: block; margin-left: auto; margin-right: auto; } .align-left { text-align: left; } .align-center { text-align: center; } .align-default { text-align: center; } .align-right { text-align: right; } /* -- sidebars -------------------------------------------------------------- */ div.sidebar, aside.sidebar { margin: 0 0 0.5em 1em; border: 1px solid #ddb; padding: 7px; background-color: #ffe; width: 40%; float: right; clear: right; overflow-x: auto; } p.sidebar-title { font-weight: bold; } nav.contents, aside.topic, div.admonition, div.topic, blockquote { clear: left; } /* -- topics ---------------------------------------------------------------- */ nav.contents, aside.topic, div.topic { border: 1px solid #ccc; padding: 7px; margin: 10px 0 10px 0; } p.topic-title { font-size: 1.1em; font-weight: bold; margin-top: 10px; } /* -- admonitions ----------------------------------------------------------- */ div.admonition { margin-top: 10px; margin-bottom: 10px; padding: 7px; } div.admonition dt { font-weight: bold; } p.admonition-title { margin: 0px 10px 5px 0px; font-weight: bold; } div.body p.centered { text-align: center; margin-top: 25px; } /* -- content of sidebars/topics/admonitions -------------------------------- */ div.sidebar > :last-child, aside.sidebar > :last-child, nav.contents > :last-child, aside.topic > :last-child, div.topic > :last-child, div.admonition > :last-child { margin-bottom: 0; } div.sidebar::after, aside.sidebar::after, nav.contents::after, aside.topic::after, div.topic::after, div.admonition::after, blockquote::after { display: block; content: ''; clear: both; } /* -- tables ---------------------------------------------------------------- */ table.docutils { margin-top: 10px; margin-bottom: 10px; border: 0; border-collapse: collapse; } table.align-center { margin-left: auto; margin-right: auto; } table.align-default { margin-left: auto; margin-right: auto; } table caption span.caption-number { font-style: italic; } table caption span.caption-text { } table.docutils td, table.docutils th { padding: 1px 8px 1px 5px; border-top: 0; border-left: 0; border-right: 0; border-bottom: 1px solid #aaa; } th { text-align: left; padding-right: 5px; } table.citation { border-left: solid 1px gray; margin-left: 1px; } table.citation td { border-bottom: none; } th > :first-child, td > :first-child { margin-top: 0px; } th > :last-child, td > :last-child { margin-bottom: 0px; } /* -- figures --------------------------------------------------------------- */ div.figure, figure { margin: 0.5em; padding: 0.5em; } div.figure p.caption, figcaption { padding: 0.3em; } div.figure p.caption span.caption-number, figcaption span.caption-number { font-style: italic; } div.figure p.caption span.caption-text, figcaption span.caption-text { } /* -- field list styles ----------------------------------------------------- */ table.field-list td, table.field-list th { border: 0 !important; } .field-list ul { margin: 0; padding-left: 1em; } .field-list p { margin: 0; } .field-name { -moz-hyphens: manual; -ms-hyphens: manual; -webkit-hyphens: manual; hyphens: manual; } /* -- hlist styles ---------------------------------------------------------- */ table.hlist { margin: 1em 0; } table.hlist td { vertical-align: top; } /* -- object description styles --------------------------------------------- */ .sig { font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; } .sig-name, code.descname { background-color: transparent; font-weight: bold; } .sig-name { font-size: 1.1em; } code.descname { font-size: 1.2em; } .sig-prename, code.descclassname { background-color: transparent; } .optional { font-size: 1.3em; } .sig-paren { font-size: larger; } .sig-param.n { font-style: italic; } /* C++ specific styling */ .sig-inline.c-texpr, .sig-inline.cpp-texpr { font-family: unset; } .sig.c .k, .sig.c .kt, .sig.cpp .k, .sig.cpp .kt { color: #0033B3; } .sig.c .m, .sig.cpp .m { color: #1750EB; } .sig.c .s, .sig.c .sc, .sig.cpp .s, .sig.cpp .sc { color: #067D17; } /* -- other body styles ----------------------------------------------------- */ ol.arabic { list-style: decimal; } ol.loweralpha { list-style: lower-alpha; } ol.upperalpha { list-style: upper-alpha; } ol.lowerroman { list-style: lower-roman; } ol.upperroman { list-style: upper-roman; } :not(li) > ol > li:first-child > :first-child, :not(li) > ul > li:first-child > :first-child { margin-top: 0px; } :not(li) > ol > li:last-child > :last-child, :not(li) > ul > li:last-child > :last-child { margin-bottom: 0px; } ol.simple ol p, ol.simple ul p, ul.simple ol p, ul.simple ul p { margin-top: 0; } ol.simple > li:not(:first-child) > p, ul.simple > li:not(:first-child) > p { margin-top: 0; } ol.simple p, ul.simple p { margin-bottom: 0; } aside.footnote > span, div.citation > span { float: left; } aside.footnote > span:last-of-type, div.citation > span:last-of-type { padding-right: 0.5em; } aside.footnote > p { margin-left: 2em; } div.citation > p { margin-left: 4em; } aside.footnote > p:last-of-type, div.citation > p:last-of-type { margin-bottom: 0em; } aside.footnote > p:last-of-type:after, div.citation > p:last-of-type:after { content: ""; clear: both; } dl.field-list { display: grid; grid-template-columns: fit-content(30%) auto; } dl.field-list > dt { font-weight: bold; word-break: break-word; padding-left: 0.5em; padding-right: 5px; } dl.field-list > dd { padding-left: 0.5em; margin-top: 0em; margin-left: 0em; margin-bottom: 0em; } dl { margin-bottom: 15px; } dd > :first-child { margin-top: 0px; } dd ul, dd table { margin-bottom: 10px; } dd { margin-top: 3px; margin-bottom: 10px; margin-left: 30px; } dl > dd:last-child, dl > dd:last-child > :last-child { margin-bottom: 0; } dt:target, span.highlighted { background-color: #fbe54e; } rect.highlighted { fill: #fbe54e; } dl.glossary dt { font-weight: bold; font-size: 1.1em; } .versionmodified { font-style: italic; } .system-message { background-color: #fda; padding: 5px; border: 3px solid red; } .footnote:target { background-color: #ffa; } .line-block { display: block; margin-top: 1em; margin-bottom: 1em; } .line-block .line-block { margin-top: 0; margin-bottom: 0; margin-left: 1.5em; } .guilabel, .menuselection { font-family: sans-serif; } .accelerator { text-decoration: underline; } .classifier { font-style: oblique; } .classifier:before { font-style: normal; margin: 0 0.5em; content: ":"; display: inline-block; } abbr, acronym { border-bottom: dotted 1px; cursor: help; } /* -- code displays --------------------------------------------------------- */ pre { overflow: auto; overflow-y: hidden; /* fixes display issues on Chrome browsers */ } pre, div[class*="highlight-"] { clear: both; } span.pre { -moz-hyphens: none; -ms-hyphens: none; -webkit-hyphens: none; hyphens: none; white-space: nowrap; } div[class*="highlight-"] { margin: 1em 0; } td.linenos pre { border: 0; background-color: transparent; color: #aaa; } table.highlighttable { display: block; } table.highlighttable tbody { display: block; } table.highlighttable tr { display: flex; } table.highlighttable td { margin: 0; padding: 0; } table.highlighttable td.linenos { padding-right: 0.5em; } table.highlighttable td.code { flex: 1; overflow: hidden; } .highlight .hll { display: block; } div.highlight pre, table.highlighttable pre { margin: 0; } div.code-block-caption + div { margin-top: 0; } div.code-block-caption { margin-top: 1em; padding: 2px 5px; font-size: small; } div.code-block-caption code { background-color: transparent; } table.highlighttable td.linenos, span.linenos, div.highlight span.gp { /* gp: Generic.Prompt */ user-select: none; -webkit-user-select: text; /* Safari fallback only */ -webkit-user-select: none; /* Chrome/Safari */ -moz-user-select: none; /* Firefox */ -ms-user-select: none; /* IE10+ */ } div.code-block-caption span.caption-number { padding: 0.1em 0.3em; font-style: italic; } div.code-block-caption span.caption-text { } div.literal-block-wrapper { margin: 1em 0; } code.xref, a code { background-color: transparent; font-weight: bold; } h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { background-color: transparent; } .viewcode-link { float: right; } .viewcode-back { float: right; font-family: sans-serif; } div.viewcode-block:target { margin: -1px -10px; padding: 0 10px; } /* -- math display ---------------------------------------------------------- */ img.math { vertical-align: middle; } div.body div.math p { text-align: center; } span.eqno { float: right; } span.eqno a.headerlink { position: absolute; z-index: 1; } div.math:hover a.headerlink { visibility: visible; } /* -- printout stylesheet --------------------------------------------------- */ @media print { div.document, div.documentwrapper, div.bodywrapper { margin: 0 !important; width: 100%; } div.sphinxsidebar, div.related, div.footer, #top-link { display: none; } }
-
-
-
@@ -0,0 +1,1 @@.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
-
-
-
@@ -0,0 +1,16 @@.rst-content .admonition .admonition-title:before { content: none; } .rst-content .admonition-theorem .admonition-title:before { content: none; } .rst-content .admonition-proof .admonition-title:before { content: none; } code.literal { color: #404040 !important; background-color: #fbfbfb !important; }
-
-
-
-
-
-
-
-
@@ -0,0 +1,2671 @@<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > <svg> <metadata> Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 By ,,, Copyright Dave Gandy 2016. All rights reserved. </metadata> <defs> <font id="FontAwesome" horiz-adv-x="1536" > <font-face font-family="FontAwesome" font-weight="400" font-stretch="normal" units-per-em="1792" panose-1="0 0 0 0 0 0 0 0 0 0" ascent="1536" descent="-256" bbox="-1.02083 -256.962 2304.6 1537.02" underline-thickness="0" underline-position="0" unicode-range="U+0020-F500" /> <missing-glyph horiz-adv-x="896" d="M224 112h448v1312h-448v-1312zM112 0v1536h672v-1536h-672z" /> <glyph glyph-name=".notdef" horiz-adv-x="896" d="M224 112h448v1312h-448v-1312zM112 0v1536h672v-1536h-672z" /> <glyph glyph-name=".null" horiz-adv-x="0" /> <glyph glyph-name="nonmarkingreturn" horiz-adv-x="597" /> <glyph glyph-name="space" unicode=" " horiz-adv-x="448" /> <glyph glyph-name="dieresis" unicode="¨" horiz-adv-x="1792" /> <glyph glyph-name="copyright" unicode="©" horiz-adv-x="1792" /> <glyph glyph-name="registered" unicode="®" horiz-adv-x="1792" /> <glyph glyph-name="acute" unicode="´" horiz-adv-x="1792" /> <glyph glyph-name="AE" unicode="Æ" horiz-adv-x="1792" /> <glyph glyph-name="Oslash" unicode="Ø" horiz-adv-x="1792" /> <glyph glyph-name="trademark" unicode="™" horiz-adv-x="1792" /> <glyph glyph-name="infinity" unicode="∞" horiz-adv-x="1792" /> <glyph glyph-name="notequal" unicode="≠" horiz-adv-x="1792" /> <glyph glyph-name="glass" unicode="" horiz-adv-x="1792" d="M1699 1350q0 -35 -43 -78l-632 -632v-768h320q26 0 45 -19t19 -45t-19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45t45 19h320v768l-632 632q-43 43 -43 78q0 23 18 36.5t38 17.5t43 4h1408q23 0 43 -4t38 -17.5t18 -36.5z" /> <glyph glyph-name="music" unicode="" d="M1536 1312v-1120q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v537l-768 -237v-709q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89 t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v967q0 31 19 56.5t49 35.5l832 256q12 4 28 4q40 0 68 -28t28 -68z" /> <glyph glyph-name="search" unicode="" horiz-adv-x="1664" d="M1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -52 -38 -90t-90 -38q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5 t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" /> <glyph glyph-name="envelope" unicode="" horiz-adv-x="1792" d="M1664 32v768q-32 -36 -69 -66q-268 -206 -426 -338q-51 -43 -83 -67t-86.5 -48.5t-102.5 -24.5h-1h-1q-48 0 -102.5 24.5t-86.5 48.5t-83 67q-158 132 -426 338q-37 30 -69 66v-768q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1664 1083v11v13.5t-0.5 13 t-3 12.5t-5.5 9t-9 7.5t-14 2.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5q0 -168 147 -284q193 -152 401 -317q6 -5 35 -29.5t46 -37.5t44.5 -31.5t50.5 -27.5t43 -9h1h1q20 0 43 9t50.5 27.5t44.5 31.5t46 37.5t35 29.5q208 165 401 317q54 43 100.5 115.5t46.5 131.5z M1792 1120v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" /> <glyph glyph-name="heart" unicode="" horiz-adv-x="1792" d="M896 -128q-26 0 -44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124t127 -344q0 -221 -229 -450l-623 -600 q-18 -18 -44 -18z" /> <glyph glyph-name="star" unicode="" horiz-adv-x="1664" d="M1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -21 -10.5 -35.5t-30.5 -14.5q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455 l502 -73q56 -9 56 -46z" /> <glyph glyph-name="star_empty" unicode="" horiz-adv-x="1664" d="M1137 532l306 297l-422 62l-189 382l-189 -382l-422 -62l306 -297l-73 -421l378 199l377 -199zM1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -50 -41 -50q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500 l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455l502 -73q56 -9 56 -46z" /> <glyph glyph-name="user" unicode="" horiz-adv-x="1280" d="M1280 137q0 -109 -62.5 -187t-150.5 -78h-854q-88 0 -150.5 78t-62.5 187q0 85 8.5 160.5t31.5 152t58.5 131t94 89t134.5 34.5q131 -128 313 -128t313 128q76 0 134.5 -34.5t94 -89t58.5 -131t31.5 -152t8.5 -160.5zM1024 1024q0 -159 -112.5 -271.5t-271.5 -112.5 t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" /> <glyph glyph-name="film" unicode="" horiz-adv-x="1920" d="M384 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 320v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 704v128q0 26 -19 45t-45 19h-128 q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 -64v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM384 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45 t45 -19h128q26 0 45 19t19 45zM1792 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 704v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1792 320v128 q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 704v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19 t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1920 1248v-1344q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1344q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" /> <glyph glyph-name="th_large" unicode="" horiz-adv-x="1664" d="M768 512v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM768 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 512v-384q0 -52 -38 -90t-90 -38 h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" /> <glyph glyph-name="th" unicode="" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 288v-192q0 -40 -28 -68t-68 -28h-320 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68z" /> <glyph glyph-name="th_list" unicode="" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-960 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h960q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68z" /> <glyph glyph-name="ok" unicode="" horiz-adv-x="1792" d="M1671 970q0 -40 -28 -68l-724 -724l-136 -136q-28 -28 -68 -28t-68 28l-136 136l-362 362q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -295l656 657q28 28 68 28t68 -28l136 -136q28 -28 28 -68z" /> <glyph glyph-name="remove" unicode="" horiz-adv-x="1408" d="M1298 214q0 -40 -28 -68l-136 -136q-28 -28 -68 -28t-68 28l-294 294l-294 -294q-28 -28 -68 -28t-68 28l-136 136q-28 28 -28 68t28 68l294 294l-294 294q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -294l294 294q28 28 68 28t68 -28l136 -136q28 -28 28 -68 t-28 -68l-294 -294l294 -294q28 -28 28 -68z" /> <glyph glyph-name="zoom_in" unicode="" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-224q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v224h-224q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h224v224q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5v-224h224 q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5 t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" /> <glyph glyph-name="zoom_out" unicode="" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-576q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h576q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5z M1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z " /> <glyph glyph-name="off" unicode="" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61t-298 61t-245 164t-164 245t-61 298q0 182 80.5 343t226.5 270q43 32 95.5 25t83.5 -50q32 -42 24.5 -94.5t-49.5 -84.5q-98 -74 -151.5 -181t-53.5 -228q0 -104 40.5 -198.5t109.5 -163.5t163.5 -109.5 t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5q0 121 -53.5 228t-151.5 181q-42 32 -49.5 84.5t24.5 94.5q31 43 84 50t95 -25q146 -109 226.5 -270t80.5 -343zM896 1408v-640q0 -52 -38 -90t-90 -38t-90 38t-38 90v640q0 52 38 90t90 38t90 -38t38 -90z" /> <glyph glyph-name="signal" unicode="" horiz-adv-x="1792" d="M256 96v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 224v-320q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 480v-576q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1408 864v-960q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1376v-1472q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1472q0 14 9 23t23 9h192q14 0 23 -9t9 -23z" /> <glyph glyph-name="cog" unicode="" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1536 749v-222q0 -12 -8 -23t-20 -13l-185 -28q-19 -54 -39 -91q35 -50 107 -138q10 -12 10 -25t-9 -23q-27 -37 -99 -108t-94 -71q-12 0 -26 9l-138 108q-44 -23 -91 -38 q-16 -136 -29 -186q-7 -28 -36 -28h-222q-14 0 -24.5 8.5t-11.5 21.5l-28 184q-49 16 -90 37l-141 -107q-10 -9 -25 -9q-14 0 -25 11q-126 114 -165 168q-7 10 -7 23q0 12 8 23q15 21 51 66.5t54 70.5q-27 50 -41 99l-183 27q-13 2 -21 12.5t-8 23.5v222q0 12 8 23t19 13 l186 28q14 46 39 92q-40 57 -107 138q-10 12 -10 24q0 10 9 23q26 36 98.5 107.5t94.5 71.5q13 0 26 -10l138 -107q44 23 91 38q16 136 29 186q7 28 36 28h222q14 0 24.5 -8.5t11.5 -21.5l28 -184q49 -16 90 -37l142 107q9 9 24 9q13 0 25 -10q129 -119 165 -170q7 -8 7 -22 q0 -12 -8 -23q-15 -21 -51 -66.5t-54 -70.5q26 -50 41 -98l183 -28q13 -2 21 -12.5t8 -23.5z" /> <glyph glyph-name="trash" unicode="" horiz-adv-x="1408" d="M512 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM768 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1024 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1152 76v948h-896v-948q0 -22 7 -40.5t14.5 -27t10.5 -8.5h832q3 0 10.5 8.5t14.5 27t7 40.5zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832 q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" /> <glyph glyph-name="home" unicode="" horiz-adv-x="1664" d="M1408 544v-480q0 -26 -19 -45t-45 -19h-384v384h-256v-384h-384q-26 0 -45 19t-19 45v480q0 1 0.5 3t0.5 3l575 474l575 -474q1 -2 1 -6zM1631 613l-62 -74q-8 -9 -21 -11h-3q-13 0 -21 7l-692 577l-692 -577q-12 -8 -24 -7q-13 2 -21 11l-62 74q-8 10 -7 23.5t11 21.5 l719 599q32 26 76 26t76 -26l244 -204v195q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-408l219 -182q10 -8 11 -21.5t-7 -23.5z" /> <glyph glyph-name="file_alt" unicode="" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z " /> <glyph glyph-name="time" unicode="" d="M896 992v-448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="road" unicode="" horiz-adv-x="1920" d="M1111 540v4l-24 320q-1 13 -11 22.5t-23 9.5h-186q-13 0 -23 -9.5t-11 -22.5l-24 -320v-4q-1 -12 8 -20t21 -8h244q12 0 21 8t8 20zM1870 73q0 -73 -46 -73h-704q13 0 22 9.5t8 22.5l-20 256q-1 13 -11 22.5t-23 9.5h-272q-13 0 -23 -9.5t-11 -22.5l-20 -256 q-1 -13 8 -22.5t22 -9.5h-704q-46 0 -46 73q0 54 26 116l417 1044q8 19 26 33t38 14h339q-13 0 -23 -9.5t-11 -22.5l-15 -192q-1 -14 8 -23t22 -9h166q13 0 22 9t8 23l-15 192q-1 13 -11 22.5t-23 9.5h339q20 0 38 -14t26 -33l417 -1044q26 -62 26 -116z" /> <glyph glyph-name="download_alt" unicode="" horiz-adv-x="1664" d="M1280 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 416v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h465l135 -136 q58 -56 136 -56t136 56l136 136h464q40 0 68 -28t28 -68zM1339 985q17 -41 -14 -70l-448 -448q-18 -19 -45 -19t-45 19l-448 448q-31 29 -14 70q17 39 59 39h256v448q0 26 19 45t45 19h256q26 0 45 -19t19 -45v-448h256q42 0 59 -39z" /> <glyph glyph-name="download" unicode="" d="M1120 608q0 -12 -10 -24l-319 -319q-11 -9 -23 -9t-23 9l-320 320q-15 16 -7 35q8 20 30 20h192v352q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-352h192q14 0 23 -9t9 -23zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273 t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="upload" unicode="" d="M1118 660q-8 -20 -30 -20h-192v-352q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v352h-192q-14 0 -23 9t-9 23q0 12 10 24l319 319q11 9 23 9t23 -9l320 -320q15 -16 7 -35zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198 t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="inbox" unicode="" d="M1023 576h316q-1 3 -2.5 8.5t-2.5 7.5l-212 496h-708l-212 -496q-1 -3 -2.5 -8.5t-2.5 -7.5h316l95 -192h320zM1536 546v-482q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v482q0 62 25 123l238 552q10 25 36.5 42t52.5 17h832q26 0 52.5 -17t36.5 -42l238 -552 q25 -61 25 -123z" /> <glyph glyph-name="play_circle" unicode="" d="M1184 640q0 -37 -32 -55l-544 -320q-15 -9 -32 -9q-16 0 -32 8q-32 19 -32 56v640q0 37 32 56q33 18 64 -1l544 -320q32 -18 32 -55zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="repeat" unicode="" d="M1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l138 138q-148 137 -349 137q-104 0 -198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5q119 0 225 52t179 147q7 10 23 12q15 0 25 -9 l137 -138q9 -8 9.5 -20.5t-7.5 -22.5q-109 -132 -264 -204.5t-327 -72.5q-156 0 -298 61t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q147 0 284.5 -55.5t244.5 -156.5l130 129q29 31 70 14q39 -17 39 -59z" /> <glyph glyph-name="refresh" unicode="" d="M1511 480q0 -5 -1 -7q-64 -268 -268 -434.5t-478 -166.5q-146 0 -282.5 55t-243.5 157l-129 -129q-19 -19 -45 -19t-45 19t-19 45v448q0 26 19 45t45 19h448q26 0 45 -19t19 -45t-19 -45l-137 -137q71 -66 161 -102t187 -36q134 0 250 65t186 179q11 17 53 117 q8 23 30 23h192q13 0 22.5 -9.5t9.5 -22.5zM1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-26 0 -45 19t-19 45t19 45l138 138q-148 137 -349 137q-134 0 -250 -65t-186 -179q-11 -17 -53 -117q-8 -23 -30 -23h-199q-13 0 -22.5 9.5t-9.5 22.5v7q65 268 270 434.5t480 166.5 q146 0 284 -55.5t245 -156.5l130 129q19 19 45 19t45 -19t19 -45z" /> <glyph glyph-name="list_alt" unicode="" horiz-adv-x="1792" d="M384 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M384 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1536 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5z M1536 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5zM1536 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5 t9.5 -22.5zM1664 160v832q0 13 -9.5 22.5t-22.5 9.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 1248v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47 t47 -113z" /> <glyph glyph-name="lock" unicode="" horiz-adv-x="1152" d="M320 768h512v192q0 106 -75 181t-181 75t-181 -75t-75 -181v-192zM1152 672v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v192q0 184 132 316t316 132t316 -132t132 -316v-192h32q40 0 68 -28t28 -68z" /> <glyph glyph-name="flag" unicode="" horiz-adv-x="1792" d="M320 1280q0 -72 -64 -110v-1266q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v1266q-64 38 -64 110q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -25 -12.5 -38.5t-39.5 -27.5q-215 -116 -369 -116q-61 0 -123.5 22t-108.5 48 t-115.5 48t-142.5 22q-192 0 -464 -146q-17 -9 -33 -9q-26 0 -45 19t-19 45v742q0 32 31 55q21 14 79 43q236 120 421 120q107 0 200 -29t219 -88q38 -19 88 -19q54 0 117.5 21t110 47t88 47t54.5 21q26 0 45 -19t19 -45z" /> <glyph glyph-name="headphones" unicode="" horiz-adv-x="1664" d="M1664 650q0 -166 -60 -314l-20 -49l-185 -33q-22 -83 -90.5 -136.5t-156.5 -53.5v-32q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-32q71 0 130 -35.5t93 -95.5l68 12q29 95 29 193q0 148 -88 279t-236.5 209t-315.5 78 t-315.5 -78t-236.5 -209t-88 -279q0 -98 29 -193l68 -12q34 60 93 95.5t130 35.5v32q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v32q-88 0 -156.5 53.5t-90.5 136.5l-185 33l-20 49q-60 148 -60 314q0 151 67 291t179 242.5 t266 163.5t320 61t320 -61t266 -163.5t179 -242.5t67 -291z" /> <glyph glyph-name="volume_off" unicode="" horiz-adv-x="768" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45z" /> <glyph glyph-name="volume_down" unicode="" horiz-adv-x="1152" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 36 t12 56.5t-12 56.5t-29 36t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142z" /> <glyph glyph-name="volume_up" unicode="" horiz-adv-x="1664" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 36 t12 56.5t-12 56.5t-29 36t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142zM1408 640q0 -153 -85 -282.5t-225 -188.5q-13 -5 -25 -5q-27 0 -46 19t-19 45q0 39 39 59q56 29 76 44q74 54 115.5 135.5t41.5 173.5t-41.5 173.5 t-115.5 135.5q-20 15 -76 44q-39 20 -39 59q0 26 19 45t45 19q13 0 26 -5q140 -59 225 -188.5t85 -282.5zM1664 640q0 -230 -127 -422.5t-338 -283.5q-13 -5 -26 -5q-26 0 -45 19t-19 45q0 36 39 59q7 4 22.5 10.5t22.5 10.5q46 25 82 51q123 91 192 227t69 289t-69 289 t-192 227q-36 26 -82 51q-7 4 -22.5 10.5t-22.5 10.5q-39 23 -39 59q0 26 19 45t45 19q13 0 26 -5q211 -91 338 -283.5t127 -422.5z" /> <glyph glyph-name="qrcode" unicode="" horiz-adv-x="1408" d="M384 384v-128h-128v128h128zM384 1152v-128h-128v128h128zM1152 1152v-128h-128v128h128zM128 129h384v383h-384v-383zM128 896h384v384h-384v-384zM896 896h384v384h-384v-384zM640 640v-640h-640v640h640zM1152 128v-128h-128v128h128zM1408 128v-128h-128v128h128z M1408 640v-384h-384v128h-128v-384h-128v640h384v-128h128v128h128zM640 1408v-640h-640v640h640zM1408 1408v-640h-640v640h640z" /> <glyph glyph-name="barcode" unicode="" horiz-adv-x="1792" d="M63 0h-63v1408h63v-1408zM126 1h-32v1407h32v-1407zM220 1h-31v1407h31v-1407zM377 1h-31v1407h31v-1407zM534 1h-62v1407h62v-1407zM660 1h-31v1407h31v-1407zM723 1h-31v1407h31v-1407zM786 1h-31v1407h31v-1407zM943 1h-63v1407h63v-1407zM1100 1h-63v1407h63v-1407z M1226 1h-63v1407h63v-1407zM1352 1h-63v1407h63v-1407zM1446 1h-63v1407h63v-1407zM1635 1h-94v1407h94v-1407zM1698 1h-32v1407h32v-1407zM1792 0h-63v1408h63v-1408z" /> <glyph glyph-name="tag" unicode="" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91z" /> <glyph glyph-name="tags" unicode="" horiz-adv-x="1920" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91zM1899 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-36 0 -59 14t-53 45l470 470q37 37 37 90q0 52 -37 91l-715 714q-38 38 -102 64.5t-117 26.5h224q53 0 117 -26.5t102 -64.5l715 -714q37 -39 37 -91z" /> <glyph glyph-name="book" unicode="" horiz-adv-x="1664" d="M1639 1058q40 -57 18 -129l-275 -906q-19 -64 -76.5 -107.5t-122.5 -43.5h-923q-77 0 -148.5 53.5t-99.5 131.5q-24 67 -2 127q0 4 3 27t4 37q1 8 -3 21.5t-3 19.5q2 11 8 21t16.5 23.5t16.5 23.5q23 38 45 91.5t30 91.5q3 10 0.5 30t-0.5 28q3 11 17 28t17 23 q21 36 42 92t25 90q1 9 -2.5 32t0.5 28q4 13 22 30.5t22 22.5q19 26 42.5 84.5t27.5 96.5q1 8 -3 25.5t-2 26.5q2 8 9 18t18 23t17 21q8 12 16.5 30.5t15 35t16 36t19.5 32t26.5 23.5t36 11.5t47.5 -5.5l-1 -3q38 9 51 9h761q74 0 114 -56t18 -130l-274 -906 q-36 -119 -71.5 -153.5t-128.5 -34.5h-869q-27 0 -38 -15q-11 -16 -1 -43q24 -70 144 -70h923q29 0 56 15.5t35 41.5l300 987q7 22 5 57q38 -15 59 -43zM575 1056q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5 t-16.5 -22.5zM492 800q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5t-16.5 -22.5z" /> <glyph glyph-name="bookmark" unicode="" horiz-adv-x="1280" d="M1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289q0 34 19.5 62t52.5 41q21 9 44 9h1048z" /> <glyph glyph-name="print" unicode="" horiz-adv-x="1664" d="M384 0h896v256h-896v-256zM384 640h896v384h-160q-40 0 -68 28t-28 68v160h-640v-640zM1536 576q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 576v-416q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-160q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68 v160h-224q-13 0 -22.5 9.5t-9.5 22.5v416q0 79 56.5 135.5t135.5 56.5h64v544q0 40 28 68t68 28h672q40 0 88 -20t76 -48l152 -152q28 -28 48 -76t20 -88v-256h64q79 0 135.5 -56.5t56.5 -135.5z" /> <glyph glyph-name="camera" unicode="" horiz-adv-x="1920" d="M960 864q119 0 203.5 -84.5t84.5 -203.5t-84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5zM1664 1280q106 0 181 -75t75 -181v-896q0 -106 -75 -181t-181 -75h-1408q-106 0 -181 75t-75 181v896q0 106 75 181t181 75h224l51 136 q19 49 69.5 84.5t103.5 35.5h512q53 0 103.5 -35.5t69.5 -84.5l51 -136h224zM960 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> <glyph glyph-name="font" unicode="" horiz-adv-x="1664" d="M725 977l-170 -450q33 0 136.5 -2t160.5 -2q19 0 57 2q-87 253 -184 452zM0 -128l2 79q23 7 56 12.5t57 10.5t49.5 14.5t44.5 29t31 50.5l237 616l280 724h75h53q8 -14 11 -21l205 -480q33 -78 106 -257.5t114 -274.5q15 -34 58 -144.5t72 -168.5q20 -45 35 -57 q19 -15 88 -29.5t84 -20.5q6 -38 6 -57q0 -5 -0.5 -13.5t-0.5 -12.5q-63 0 -190 8t-191 8q-76 0 -215 -7t-178 -8q0 43 4 78l131 28q1 0 12.5 2.5t15.5 3.5t14.5 4.5t15 6.5t11 8t9 11t2.5 14q0 16 -31 96.5t-72 177.5t-42 100l-450 2q-26 -58 -76.5 -195.5t-50.5 -162.5 q0 -22 14 -37.5t43.5 -24.5t48.5 -13.5t57 -8.5t41 -4q1 -19 1 -58q0 -9 -2 -27q-58 0 -174.5 10t-174.5 10q-8 0 -26.5 -4t-21.5 -4q-80 -14 -188 -14z" /> <glyph glyph-name="bold" unicode="" horiz-adv-x="1408" d="M555 15q74 -32 140 -32q376 0 376 335q0 114 -41 180q-27 44 -61.5 74t-67.5 46.5t-80.5 25t-84 10.5t-94.5 2q-73 0 -101 -10q0 -53 -0.5 -159t-0.5 -158q0 -8 -1 -67.5t-0.5 -96.5t4.5 -83.5t12 -66.5zM541 761q42 -7 109 -7q82 0 143 13t110 44.5t74.5 89.5t25.5 142 q0 70 -29 122.5t-79 82t-108 43.5t-124 14q-50 0 -130 -13q0 -50 4 -151t4 -152q0 -27 -0.5 -80t-0.5 -79q0 -46 1 -69zM0 -128l2 94q15 4 85 16t106 27q7 12 12.5 27t8.5 33.5t5.5 32.5t3 37.5t0.5 34v35.5v30q0 982 -22 1025q-4 8 -22 14.5t-44.5 11t-49.5 7t-48.5 4.5 t-30.5 3l-4 83q98 2 340 11.5t373 9.5q23 0 68 -0.5t68 -0.5q70 0 136.5 -13t128.5 -42t108 -71t74 -104.5t28 -137.5q0 -52 -16.5 -95.5t-39 -72t-64.5 -57.5t-73 -45t-84 -40q154 -35 256.5 -134t102.5 -248q0 -100 -35 -179.5t-93.5 -130.5t-138 -85.5t-163.5 -48.5 t-176 -14q-44 0 -132 3t-132 3q-106 0 -307 -11t-231 -12z" /> <glyph glyph-name="italic" unicode="" horiz-adv-x="1024" d="M0 -126l17 85q22 7 61.5 16.5t72 19t59.5 23.5q28 35 41 101q1 7 62 289t114 543.5t52 296.5v25q-24 13 -54.5 18.5t-69.5 8t-58 5.5l19 103q33 -2 120 -6.5t149.5 -7t120.5 -2.5q48 0 98.5 2.5t121 7t98.5 6.5q-5 -39 -19 -89q-30 -10 -101.5 -28.5t-108.5 -33.5 q-8 -19 -14 -42.5t-9 -40t-7.5 -45.5t-6.5 -42q-27 -148 -87.5 -419.5t-77.5 -355.5q-2 -9 -13 -58t-20 -90t-16 -83.5t-6 -57.5l1 -18q17 -4 185 -31q-3 -44 -16 -99q-11 0 -32.5 -1.5t-32.5 -1.5q-29 0 -87 10t-86 10q-138 2 -206 2q-51 0 -143 -9t-121 -11z" /> <glyph glyph-name="text_height" unicode="" horiz-adv-x="1792" d="M1744 128q33 0 42 -18.5t-11 -44.5l-126 -162q-20 -26 -49 -26t-49 26l-126 162q-20 26 -11 44.5t42 18.5h80v1024h-80q-33 0 -42 18.5t11 44.5l126 162q20 26 49 26t49 -26l126 -162q20 -26 11 -44.5t-42 -18.5h-80v-1024h80zM81 1407l54 -27q12 -5 211 -5q44 0 132 2 t132 2q36 0 107.5 -0.5t107.5 -0.5h293q6 0 21 -0.5t20.5 0t16 3t17.5 9t15 17.5l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 48t-14.5 73.5t-7.5 35.5q-6 8 -12 12.5t-15.5 6t-13 2.5t-18 0.5t-16.5 -0.5 q-17 0 -66.5 0.5t-74.5 0.5t-64 -2t-71 -6q-9 -81 -8 -136q0 -94 2 -388t2 -455q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 q19 42 19 383q0 101 -3 303t-3 303v117q0 2 0.5 15.5t0.5 25t-1 25.5t-3 24t-5 14q-11 12 -162 12q-33 0 -93 -12t-80 -26q-19 -13 -34 -72.5t-31.5 -111t-42.5 -53.5q-42 26 -56 44v383z" /> <glyph glyph-name="text_width" unicode="" d="M81 1407l54 -27q12 -5 211 -5q44 0 132 2t132 2q70 0 246.5 1t304.5 0.5t247 -4.5q33 -1 56 31l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 47.5t-15 73.5t-7 36q-10 13 -27 19q-5 2 -66 2q-30 0 -93 1t-103 1 t-94 -2t-96 -7q-9 -81 -8 -136l1 -152v52q0 -55 1 -154t1.5 -180t0.5 -153q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 q7 16 11.5 74t6 145.5t1.5 155t-0.5 153.5t-0.5 89q0 7 -2.5 21.5t-2.5 22.5q0 7 0.5 44t1 73t0 76.5t-3 67.5t-6.5 32q-11 12 -162 12q-41 0 -163 -13.5t-138 -24.5q-19 -12 -34 -71.5t-31.5 -111.5t-42.5 -54q-42 26 -56 44v383zM1310 125q12 0 42 -19.5t57.5 -41.5 t59.5 -49t36 -30q26 -21 26 -49t-26 -49q-4 -3 -36 -30t-59.5 -49t-57.5 -41.5t-42 -19.5q-13 0 -20.5 10.5t-10 28.5t-2.5 33.5t1.5 33t1.5 19.5h-1024q0 -2 1.5 -19.5t1.5 -33t-2.5 -33.5t-10 -28.5t-20.5 -10.5q-12 0 -42 19.5t-57.5 41.5t-59.5 49t-36 30q-26 21 -26 49 t26 49q4 3 36 30t59.5 49t57.5 41.5t42 19.5q13 0 20.5 -10.5t10 -28.5t2.5 -33.5t-1.5 -33t-1.5 -19.5h1024q0 2 -1.5 19.5t-1.5 33t2.5 33.5t10 28.5t20.5 10.5z" /> <glyph glyph-name="align_left" unicode="" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" /> <glyph glyph-name="align_center" unicode="" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h896q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45t-45 -19 h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h640q26 0 45 -19t19 -45z" /> <glyph glyph-name="align_right" unicode="" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" /> <glyph glyph-name="align_justify" unicode="" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" /> <glyph glyph-name="list" unicode="" horiz-adv-x="1792" d="M256 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM256 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5 t9.5 -22.5zM256 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344 q13 0 22.5 -9.5t9.5 -22.5zM256 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192 q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5z" /> <glyph glyph-name="indent_left" unicode="" horiz-adv-x="1792" d="M384 992v-576q0 -13 -9.5 -22.5t-22.5 -9.5q-14 0 -23 9l-288 288q-9 9 -9 23t9 23l288 288q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" /> <glyph glyph-name="indent_right" unicode="" horiz-adv-x="1792" d="M352 704q0 -14 -9 -23l-288 -288q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v576q0 13 9.5 22.5t22.5 9.5q14 0 23 -9l288 -288q9 -9 9 -23zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" /> <glyph glyph-name="facetime_video" unicode="" horiz-adv-x="1792" d="M1792 1184v-1088q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-403 403v-166q0 -119 -84.5 -203.5t-203.5 -84.5h-704q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h704q119 0 203.5 -84.5t84.5 -203.5v-165l403 402q18 19 45 19q12 0 25 -5 q39 -17 39 -59z" /> <glyph glyph-name="picture" unicode="" horiz-adv-x="1920" d="M640 960q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 576v-448h-1408v192l320 320l160 -160l512 512zM1760 1280h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5v1216 q0 13 -9.5 22.5t-22.5 9.5zM1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" /> <glyph glyph-name="pencil" unicode="" d="M363 0l91 91l-235 235l-91 -91v-107h128v-128h107zM886 928q0 22 -22 22q-10 0 -17 -7l-542 -542q-7 -7 -7 -17q0 -22 22 -22q10 0 17 7l542 542q7 7 7 17zM832 1120l416 -416l-832 -832h-416v416zM1515 1024q0 -53 -37 -90l-166 -166l-416 416l166 165q36 38 90 38 q53 0 91 -38l235 -234q37 -39 37 -91z" /> <glyph glyph-name="map_marker" unicode="" horiz-adv-x="1024" d="M768 896q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1024 896q0 -109 -33 -179l-364 -774q-16 -33 -47.5 -52t-67.5 -19t-67.5 19t-46.5 52l-365 774q-33 70 -33 179q0 212 150 362t362 150t362 -150t150 -362z" /> <glyph glyph-name="adjust" unicode="" d="M768 96v1088q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="tint" unicode="" horiz-adv-x="1024" d="M512 384q0 36 -20 69q-1 1 -15.5 22.5t-25.5 38t-25 44t-21 50.5q-4 16 -21 16t-21 -16q-7 -23 -21 -50.5t-25 -44t-25.5 -38t-15.5 -22.5q-20 -33 -20 -69q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 512q0 -212 -150 -362t-362 -150t-362 150t-150 362 q0 145 81 275q6 9 62.5 90.5t101 151t99.5 178t83 201.5q9 30 34 47t51 17t51.5 -17t33.5 -47q28 -93 83 -201.5t99.5 -178t101 -151t62.5 -90.5q81 -127 81 -275z" /> <glyph glyph-name="edit" unicode="" horiz-adv-x="1792" d="M888 352l116 116l-152 152l-116 -116v-56h96v-96h56zM1328 1072q-16 16 -33 -1l-350 -350q-17 -17 -1 -33t33 1l350 350q17 17 1 33zM1408 478v-190q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-14 -14 -32 -8q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v126q0 13 9 22l64 64q15 15 35 7t20 -29zM1312 1216l288 -288l-672 -672h-288v288zM1756 1084l-92 -92 l-288 288l92 92q28 28 68 28t68 -28l152 -152q28 -28 28 -68t-28 -68z" /> <glyph glyph-name="share" unicode="" horiz-adv-x="1664" d="M1408 547v-259q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h255v0q13 0 22.5 -9.5t9.5 -22.5q0 -27 -26 -32q-77 -26 -133 -60q-10 -4 -16 -4h-112q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832 q66 0 113 47t47 113v214q0 19 18 29q28 13 54 37q16 16 35 8q21 -9 21 -29zM1645 1043l-384 -384q-18 -19 -45 -19q-12 0 -25 5q-39 17 -39 59v192h-160q-323 0 -438 -131q-119 -137 -74 -473q3 -23 -20 -34q-8 -2 -12 -2q-16 0 -26 13q-10 14 -21 31t-39.5 68.5t-49.5 99.5 t-38.5 114t-17.5 122q0 49 3.5 91t14 90t28 88t47 81.5t68.5 74t94.5 61.5t124.5 48.5t159.5 30.5t196.5 11h160v192q0 42 39 59q13 5 25 5q26 0 45 -19l384 -384q19 -19 19 -45t-19 -45z" /> <glyph glyph-name="check" unicode="" horiz-adv-x="1664" d="M1408 606v-318q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-10 -10 -23 -10q-3 0 -9 2q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832 q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v254q0 13 9 22l64 64q10 10 23 10q6 0 12 -3q20 -8 20 -29zM1639 1095l-814 -814q-24 -24 -57 -24t-57 24l-430 430q-24 24 -24 57t24 57l110 110q24 24 57 24t57 -24l263 -263l647 647q24 24 57 24t57 -24l110 -110 q24 -24 24 -57t-24 -57z" /> <glyph glyph-name="move" unicode="" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-384v-384h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v384h-384v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45 t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h384v384h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45t-19 -45t-45 -19h-128v-384h384v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" /> <glyph glyph-name="step_backward" unicode="" horiz-adv-x="1024" d="M979 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 10 13 19z" /> <glyph glyph-name="fast_backward" unicode="" horiz-adv-x="1792" d="M1747 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 10 13 19l710 710 q19 19 32 13t13 -32v-710q4 10 13 19z" /> <glyph glyph-name="backward" unicode="" horiz-adv-x="1664" d="M1619 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-19 19 -19 45t19 45l710 710q19 19 32 13t13 -32v-710q4 10 13 19z" /> <glyph glyph-name="play" unicode="" horiz-adv-x="1408" d="M1384 609l-1328 -738q-23 -13 -39.5 -3t-16.5 36v1472q0 26 16.5 36t39.5 -3l1328 -738q23 -13 23 -31t-23 -31z" /> <glyph glyph-name="pause" unicode="" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45zM640 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45z" /> <glyph glyph-name="stop" unicode="" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" /> <glyph glyph-name="forward" unicode="" horiz-adv-x="1664" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q9 -9 13 -19v710q0 26 13 32t32 -13l710 -710q19 -19 19 -45t-19 -45l-710 -710q-19 -19 -32 -13t-13 32v710q-4 -10 -13 -19z" /> <glyph glyph-name="fast_forward" unicode="" horiz-adv-x="1792" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q9 -9 13 -19v710q0 26 13 32t32 -13l710 -710q9 -9 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-4 -10 -13 -19l-710 -710 q-19 -19 -32 -13t-13 32v710q-4 -10 -13 -19z" /> <glyph glyph-name="step_forward" unicode="" horiz-adv-x="1024" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q9 -9 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-4 -10 -13 -19z" /> <glyph glyph-name="eject" unicode="" horiz-adv-x="1538" d="M14 557l710 710q19 19 45 19t45 -19l710 -710q19 -19 13 -32t-32 -13h-1472q-26 0 -32 13t13 32zM1473 0h-1408q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1408q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19z" /> <glyph glyph-name="chevron_left" unicode="" horiz-adv-x="1280" d="M1171 1235l-531 -531l531 -531q19 -19 19 -45t-19 -45l-166 -166q-19 -19 -45 -19t-45 19l-742 742q-19 19 -19 45t19 45l742 742q19 19 45 19t45 -19l166 -166q19 -19 19 -45t-19 -45z" /> <glyph glyph-name="chevron_right" unicode="" horiz-adv-x="1280" d="M1107 659l-742 -742q-19 -19 -45 -19t-45 19l-166 166q-19 19 -19 45t19 45l531 531l-531 531q-19 19 -19 45t19 45l166 166q19 19 45 19t45 -19l742 -742q19 -19 19 -45t-19 -45z" /> <glyph glyph-name="plus_sign" unicode="" d="M1216 576v128q0 26 -19 45t-45 19h-256v256q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-256h-256q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h256v-256q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v256h256q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5 t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="minus_sign" unicode="" d="M1216 576v128q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" /> <glyph glyph-name="remove_sign" unicode="" d="M1149 414q0 26 -19 45l-181 181l181 181q19 19 19 45q0 27 -19 46l-90 90q-19 19 -46 19q-26 0 -45 -19l-181 -181l-181 181q-19 19 -45 19q-27 0 -46 -19l-90 -90q-19 -19 -19 -46q0 -26 19 -45l181 -181l-181 -181q-19 -19 -19 -45q0 -27 19 -46l90 -90q19 -19 46 -19 q26 0 45 19l181 181l181 -181q19 -19 45 -19q27 0 46 19l90 90q19 19 19 46zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="ok_sign" unicode="" d="M1284 802q0 28 -18 46l-91 90q-19 19 -45 19t-45 -19l-408 -407l-226 226q-19 19 -45 19t-45 -19l-91 -90q-18 -18 -18 -46q0 -27 18 -45l362 -362q19 -19 45 -19q27 0 46 19l543 543q18 18 18 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="question_sign" unicode="" d="M896 160v192q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1152 832q0 88 -55.5 163t-138.5 116t-170 41q-243 0 -371 -213q-15 -24 8 -42l132 -100q7 -6 19 -6q16 0 25 12q53 68 86 92q34 24 86 24q48 0 85.5 -26t37.5 -59 q0 -38 -20 -61t-68 -45q-63 -28 -115.5 -86.5t-52.5 -125.5v-36q0 -14 9 -23t23 -9h192q14 0 23 9t9 23q0 19 21.5 49.5t54.5 49.5q32 18 49 28.5t46 35t44.5 48t28 60.5t12.5 81zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="info_sign" unicode="" d="M1024 160v160q0 14 -9 23t-23 9h-96v512q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h96v-320h-96q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h448q14 0 23 9t9 23zM896 1056v160q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23 t23 -9h192q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="screenshot" unicode="" d="M1197 512h-109q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h109q-32 108 -112.5 188.5t-188.5 112.5v-109q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v109q-108 -32 -188.5 -112.5t-112.5 -188.5h109q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-109 q32 -108 112.5 -188.5t188.5 -112.5v109q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-109q108 32 188.5 112.5t112.5 188.5zM1536 704v-128q0 -26 -19 -45t-45 -19h-143q-37 -161 -154.5 -278.5t-278.5 -154.5v-143q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v143 q-161 37 -278.5 154.5t-154.5 278.5h-143q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h143q37 161 154.5 278.5t278.5 154.5v143q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-143q161 -37 278.5 -154.5t154.5 -278.5h143q26 0 45 -19t19 -45z" /> <glyph glyph-name="remove_circle" unicode="" d="M1097 457l-146 -146q-10 -10 -23 -10t-23 10l-137 137l-137 -137q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l137 137l-137 137q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l137 -137l137 137q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 l-137 -137l137 -137q10 -10 10 -23t-10 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5 t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="ok_circle" unicode="" d="M1171 723l-422 -422q-19 -19 -45 -19t-45 19l-294 294q-19 19 -19 45t19 45l102 102q19 19 45 19t45 -19l147 -147l275 275q19 19 45 19t45 -19l102 -102q19 -19 19 -45t-19 -45zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198 t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="ban_circle" unicode="" d="M1312 643q0 161 -87 295l-754 -753q137 -89 297 -89q111 0 211.5 43.5t173.5 116.5t116 174.5t43 212.5zM313 344l755 754q-135 91 -300 91q-148 0 -273 -73t-198 -199t-73 -274q0 -162 89 -299zM1536 643q0 -157 -61 -300t-163.5 -246t-245 -164t-298.5 -61t-298.5 61 t-245 164t-163.5 246t-61 300t61 299.5t163.5 245.5t245 164t298.5 61t298.5 -61t245 -164t163.5 -245.5t61 -299.5z" /> <glyph glyph-name="arrow_left" unicode="" d="M1536 640v-128q0 -53 -32.5 -90.5t-84.5 -37.5h-704l293 -294q38 -36 38 -90t-38 -90l-75 -76q-37 -37 -90 -37q-52 0 -91 37l-651 652q-37 37 -37 90q0 52 37 91l651 650q38 38 91 38q52 0 90 -38l75 -74q38 -38 38 -91t-38 -91l-293 -293h704q52 0 84.5 -37.5 t32.5 -90.5z" /> <glyph glyph-name="arrow_right" unicode="" d="M1472 576q0 -54 -37 -91l-651 -651q-39 -37 -91 -37q-51 0 -90 37l-75 75q-38 38 -38 91t38 91l293 293h-704q-52 0 -84.5 37.5t-32.5 90.5v128q0 53 32.5 90.5t84.5 37.5h704l-293 294q-38 36 -38 90t38 90l75 75q38 38 90 38q53 0 91 -38l651 -651q37 -35 37 -90z" /> <glyph glyph-name="arrow_up" unicode="" horiz-adv-x="1664" d="M1611 565q0 -51 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-294 293v-704q0 -52 -37.5 -84.5t-90.5 -32.5h-128q-53 0 -90.5 32.5t-37.5 84.5v704l-294 -293q-36 -38 -90 -38t-90 38l-75 75q-38 38 -38 90q0 53 38 91l651 651q35 37 90 37q54 0 91 -37l651 -651 q37 -39 37 -91z" /> <glyph glyph-name="arrow_down" unicode="" horiz-adv-x="1664" d="M1611 704q0 -53 -37 -90l-651 -652q-39 -37 -91 -37q-53 0 -90 37l-651 652q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l294 -294v704q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-704l294 294q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" /> <glyph glyph-name="share_alt" unicode="" horiz-adv-x="1792" d="M1792 896q0 -26 -19 -45l-512 -512q-19 -19 -45 -19t-45 19t-19 45v256h-224q-98 0 -175.5 -6t-154 -21.5t-133 -42.5t-105.5 -69.5t-80 -101t-48.5 -138.5t-17.5 -181q0 -55 5 -123q0 -6 2.5 -23.5t2.5 -26.5q0 -15 -8.5 -25t-23.5 -10q-16 0 -28 17q-7 9 -13 22 t-13.5 30t-10.5 24q-127 285 -127 451q0 199 53 333q162 403 875 403h224v256q0 26 19 45t45 19t45 -19l512 -512q19 -19 19 -45z" /> <glyph glyph-name="resize_full" unicode="" d="M755 480q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23zM1536 1344v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332 q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45z" /> <glyph glyph-name="resize_small" unicode="" d="M768 576v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45zM1523 1248q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45 t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23z" /> <glyph glyph-name="plus" unicode="" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-416v-416q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v416h-416q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68 -28t28 -68v-416h416q40 0 68 -28t28 -68z" /> <glyph glyph-name="minus" unicode="" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-1216q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h1216q40 0 68 -28t28 -68z" /> <glyph glyph-name="asterisk" unicode="" horiz-adv-x="1664" d="M1482 486q46 -26 59.5 -77.5t-12.5 -97.5l-64 -110q-26 -46 -77.5 -59.5t-97.5 12.5l-266 153v-307q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v307l-266 -153q-46 -26 -97.5 -12.5t-77.5 59.5l-64 110q-26 46 -12.5 97.5t59.5 77.5l266 154l-266 154 q-46 26 -59.5 77.5t12.5 97.5l64 110q26 46 77.5 59.5t97.5 -12.5l266 -153v307q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-307l266 153q46 26 97.5 12.5t77.5 -59.5l64 -110q26 -46 12.5 -97.5t-59.5 -77.5l-266 -154z" /> <glyph glyph-name="exclamation_sign" unicode="" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM896 161v190q0 14 -9 23.5t-22 9.5h-192q-13 0 -23 -10t-10 -23v-190q0 -13 10 -23t23 -10h192 q13 0 22 9.5t9 23.5zM894 505l18 621q0 12 -10 18q-10 8 -24 8h-220q-14 0 -24 -8q-10 -6 -10 -18l17 -621q0 -10 10 -17.5t24 -7.5h185q14 0 23.5 7.5t10.5 17.5z" /> <glyph glyph-name="gift" unicode="" d="M928 180v56v468v192h-320v-192v-468v-56q0 -25 18 -38.5t46 -13.5h192q28 0 46 13.5t18 38.5zM472 1024h195l-126 161q-26 31 -69 31q-40 0 -68 -28t-28 -68t28 -68t68 -28zM1160 1120q0 40 -28 68t-68 28q-43 0 -69 -31l-125 -161h194q40 0 68 28t28 68zM1536 864v-320 q0 -14 -9 -23t-23 -9h-96v-416q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v416h-96q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h440q-93 0 -158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5q107 0 168 -77l128 -165l128 165q61 77 168 77q93 0 158.5 -65.5t65.5 -158.5 t-65.5 -158.5t-158.5 -65.5h440q14 0 23 -9t9 -23z" /> <glyph glyph-name="leaf" unicode="" horiz-adv-x="1792" d="M1280 832q0 26 -19 45t-45 19q-172 0 -318 -49.5t-259.5 -134t-235.5 -219.5q-19 -21 -19 -45q0 -26 19 -45t45 -19q24 0 45 19q27 24 74 71t67 66q137 124 268.5 176t313.5 52q26 0 45 19t19 45zM1792 1030q0 -95 -20 -193q-46 -224 -184.5 -383t-357.5 -268 q-214 -108 -438 -108q-148 0 -286 47q-15 5 -88 42t-96 37q-16 0 -39.5 -32t-45 -70t-52.5 -70t-60 -32q-43 0 -63.5 17.5t-45.5 59.5q-2 4 -6 11t-5.5 10t-3 9.5t-1.5 13.5q0 35 31 73.5t68 65.5t68 56t31 48q0 4 -14 38t-16 44q-9 51 -9 104q0 115 43.5 220t119 184.5 t170.5 139t204 95.5q55 18 145 25.5t179.5 9t178.5 6t163.5 24t113.5 56.5l29.5 29.5t29.5 28t27 20t36.5 16t43.5 4.5q39 0 70.5 -46t47.5 -112t24 -124t8 -96z" /> <glyph glyph-name="fire" unicode="" horiz-adv-x="1408" d="M1408 -160v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1152 896q0 -78 -24.5 -144t-64 -112.5t-87.5 -88t-96 -77.5t-87.5 -72t-64 -81.5t-24.5 -96.5q0 -96 67 -224l-4 1l1 -1 q-90 41 -160 83t-138.5 100t-113.5 122.5t-72.5 150.5t-27.5 184q0 78 24.5 144t64 112.5t87.5 88t96 77.5t87.5 72t64 81.5t24.5 96.5q0 94 -66 224l3 -1l-1 1q90 -41 160 -83t138.5 -100t113.5 -122.5t72.5 -150.5t27.5 -184z" /> <glyph glyph-name="eye_open" unicode="" horiz-adv-x="1792" d="M1664 576q-152 236 -381 353q61 -104 61 -225q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 121 61 225q-229 -117 -381 -353q133 -205 333.5 -326.5t434.5 -121.5t434.5 121.5t333.5 326.5zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5 t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1792 576q0 -34 -20 -69q-140 -230 -376.5 -368.5t-499.5 -138.5t-499.5 139t-376.5 368q-20 35 -20 69t20 69q140 229 376.5 368t499.5 139t499.5 -139t376.5 -368q20 -35 20 -69z" /> <glyph glyph-name="eye_close" unicode="" horiz-adv-x="1792" d="M555 201l78 141q-87 63 -136 159t-49 203q0 121 61 225q-229 -117 -381 -353q167 -258 427 -375zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1307 1151q0 -7 -1 -9 q-106 -189 -316 -567t-315 -566l-49 -89q-10 -16 -28 -16q-12 0 -134 70q-16 10 -16 28q0 12 44 87q-143 65 -263.5 173t-208.5 245q-20 31 -20 69t20 69q153 235 380 371t496 136q89 0 180 -17l54 97q10 16 28 16q5 0 18 -6t31 -15.5t33 -18.5t31.5 -18.5t19.5 -11.5 q16 -10 16 -27zM1344 704q0 -139 -79 -253.5t-209 -164.5l280 502q8 -45 8 -84zM1792 576q0 -35 -20 -69q-39 -64 -109 -145q-150 -172 -347.5 -267t-419.5 -95l74 132q212 18 392.5 137t301.5 307q-115 179 -282 294l63 112q95 -64 182.5 -153t144.5 -184q20 -34 20 -69z " /> <glyph glyph-name="warning_sign" unicode="" horiz-adv-x="1792" d="M1024 161v190q0 14 -9.5 23.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -23.5v-190q0 -14 9.5 -23.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 23.5zM1022 535l18 459q0 12 -10 19q-13 11 -24 11h-220q-11 0 -24 -11q-10 -7 -10 -21l17 -457q0 -10 10 -16.5t24 -6.5h185 q14 0 23.5 6.5t10.5 16.5zM1008 1469l768 -1408q35 -63 -2 -126q-17 -29 -46.5 -46t-63.5 -17h-1536q-34 0 -63.5 17t-46.5 46q-37 63 -2 126l768 1408q17 31 47 49t65 18t65 -18t47 -49z" /> <glyph glyph-name="plane" unicode="" horiz-adv-x="1408" d="M1376 1376q44 -52 12 -148t-108 -172l-161 -161l160 -696q5 -19 -12 -33l-128 -96q-7 -6 -19 -6q-4 0 -7 1q-15 3 -21 16l-279 508l-259 -259l53 -194q5 -17 -8 -31l-96 -96q-9 -9 -23 -9h-2q-15 2 -24 13l-189 252l-252 189q-11 7 -13 23q-1 13 9 25l96 97q9 9 23 9 q6 0 8 -1l194 -53l259 259l-508 279q-14 8 -17 24q-2 16 9 27l128 128q14 13 30 8l665 -159l160 160q76 76 172 108t148 -12z" /> <glyph glyph-name="calendar" unicode="" horiz-adv-x="1664" d="M128 -128h288v288h-288v-288zM480 -128h320v288h-320v-288zM128 224h288v320h-288v-320zM480 224h320v320h-320v-320zM128 608h288v288h-288v-288zM864 -128h320v288h-320v-288zM480 608h320v288h-320v-288zM1248 -128h288v288h-288v-288zM864 224h320v320h-320v-320z M512 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1248 224h288v320h-288v-320zM864 608h320v288h-320v-288zM1248 608h288v288h-288v-288zM1280 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64 q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47 h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" /> <glyph glyph-name="random" unicode="" horiz-adv-x="1792" d="M666 1055q-60 -92 -137 -273q-22 45 -37 72.5t-40.5 63.5t-51 56.5t-63 35t-81.5 14.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q250 0 410 -225zM1792 256q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192q-32 0 -85 -0.5t-81 -1t-73 1 t-71 5t-64 10.5t-63 18.5t-58 28.5t-59 40t-55 53.5t-56 69.5q59 93 136 273q22 -45 37 -72.5t40.5 -63.5t51 -56.5t63 -35t81.5 -14.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1792 1152q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5 v192h-256q-48 0 -87 -15t-69 -45t-51 -61.5t-45 -77.5q-32 -62 -78 -171q-29 -66 -49.5 -111t-54 -105t-64 -100t-74 -83t-90 -68.5t-106.5 -42t-128 -16.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q48 0 87 15t69 45t51 61.5t45 77.5q32 62 78 171q29 66 49.5 111 t54 105t64 100t74 83t90 68.5t106.5 42t128 16.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" /> <glyph glyph-name="comment" unicode="" horiz-adv-x="1792" d="M1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22q-17 -2 -30.5 9t-17.5 29v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281 q0 130 71 248.5t191 204.5t286 136.5t348 50.5q244 0 450 -85.5t326 -233t120 -321.5z" /> <glyph glyph-name="magnet" unicode="" d="M1536 704v-128q0 -201 -98.5 -362t-274 -251.5t-395.5 -90.5t-395.5 90.5t-274 251.5t-98.5 362v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-128q0 -52 23.5 -90t53.5 -57t71 -30t64 -13t44 -2t44 2t64 13t71 30t53.5 57t23.5 90v128q0 26 19 45t45 19h384 q26 0 45 -19t19 -45zM512 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45zM1536 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45z" /> <glyph glyph-name="chevron_up" unicode="" horiz-adv-x="1792" d="M1683 205l-166 -165q-19 -19 -45 -19t-45 19l-531 531l-531 -531q-19 -19 -45 -19t-45 19l-166 165q-19 19 -19 45.5t19 45.5l742 741q19 19 45 19t45 -19l742 -741q19 -19 19 -45.5t-19 -45.5z" /> <glyph glyph-name="chevron_down" unicode="" horiz-adv-x="1792" d="M1683 728l-742 -741q-19 -19 -45 -19t-45 19l-742 741q-19 19 -19 45.5t19 45.5l166 165q19 19 45 19t45 -19l531 -531l531 531q19 19 45 19t45 -19l166 -165q19 -19 19 -45.5t-19 -45.5z" /> <glyph glyph-name="retweet" unicode="" horiz-adv-x="1920" d="M1280 32q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-8 0 -13.5 2t-9 7t-5.5 8t-3 11.5t-1 11.5v13v11v160v416h-192q-26 0 -45 19t-19 45q0 24 15 41l320 384q19 22 49 22t49 -22l320 -384q15 -17 15 -41q0 -26 -19 -45t-45 -19h-192v-384h576q16 0 25 -11l160 -192q7 -10 7 -21 zM1920 448q0 -24 -15 -41l-320 -384q-20 -23 -49 -23t-49 23l-320 384q-15 17 -15 41q0 26 19 45t45 19h192v384h-576q-16 0 -25 12l-160 192q-7 9 -7 20q0 13 9.5 22.5t22.5 9.5h960q8 0 13.5 -2t9 -7t5.5 -8t3 -11.5t1 -11.5v-13v-11v-160v-416h192q26 0 45 -19t19 -45z " /> <glyph glyph-name="shopping_cart" unicode="" horiz-adv-x="1664" d="M640 0q0 -52 -38 -90t-90 -38t-90 38t-38 90t38 90t90 38t90 -38t38 -90zM1536 0q0 -52 -38 -90t-90 -38t-90 38t-38 90t38 90t90 38t90 -38t38 -90zM1664 1088v-512q0 -24 -16.5 -42.5t-40.5 -21.5l-1044 -122q13 -60 13 -70q0 -16 -24 -64h920q26 0 45 -19t19 -45 t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 11 8 31.5t16 36t21.5 40t15.5 29.5l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t19.5 -15.5t13 -24.5t8 -26t5.5 -29.5t4.5 -26h1201q26 0 45 -19t19 -45z" /> <glyph glyph-name="folder_close" unicode="" horiz-adv-x="1664" d="M1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" /> <glyph glyph-name="folder_open" unicode="" horiz-adv-x="1920" d="M1879 584q0 -31 -31 -66l-336 -396q-43 -51 -120.5 -86.5t-143.5 -35.5h-1088q-34 0 -60.5 13t-26.5 43q0 31 31 66l336 396q43 51 120.5 86.5t143.5 35.5h1088q34 0 60.5 -13t26.5 -43zM1536 928v-160h-832q-94 0 -197 -47.5t-164 -119.5l-337 -396l-5 -6q0 4 -0.5 12.5 t-0.5 12.5v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158z" /> <glyph glyph-name="resize_vertical" unicode="" horiz-adv-x="768" d="M704 1216q0 -26 -19 -45t-45 -19h-128v-1024h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v1024h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45z" /> <glyph glyph-name="resize_horizontal" unicode="" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-1024v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h1024v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" /> <glyph glyph-name="bar_chart" unicode="" horiz-adv-x="2048" d="M640 640v-512h-256v512h256zM1024 1152v-1024h-256v1024h256zM2048 0v-128h-2048v1536h128v-1408h1920zM1408 896v-768h-256v768h256zM1792 1280v-1152h-256v1152h256z" /> <glyph glyph-name="twitter_sign" unicode="" d="M1280 926q-56 -25 -121 -34q68 40 93 117q-65 -38 -134 -51q-61 66 -153 66q-87 0 -148.5 -61.5t-61.5 -148.5q0 -29 5 -48q-129 7 -242 65t-192 155q-29 -50 -29 -106q0 -114 91 -175q-47 1 -100 26v-2q0 -75 50 -133.5t123 -72.5q-29 -8 -51 -8q-13 0 -39 4 q21 -63 74.5 -104t121.5 -42q-116 -90 -261 -90q-26 0 -50 3q148 -94 322 -94q112 0 210 35.5t168 95t120.5 137t75 162t24.5 168.5q0 18 -1 27q63 45 105 109zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5 t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="facebook_sign" unicode="" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-188v595h199l30 232h-229v148q0 56 23.5 84t91.5 28l122 1v207q-63 9 -178 9q-136 0 -217.5 -80t-81.5 -226v-171h-200v-232h200v-595h-532q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960z" /> <glyph glyph-name="camera_retro" unicode="" horiz-adv-x="1792" d="M928 704q0 14 -9 23t-23 9q-66 0 -113 -47t-47 -113q0 -14 9 -23t23 -9t23 9t9 23q0 40 28 68t68 28q14 0 23 9t9 23zM1152 574q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM128 0h1536v128h-1536v-128zM1280 574q0 159 -112.5 271.5 t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM256 1216h384v128h-384v-128zM128 1024h1536v118v138h-828l-64 -128h-644v-128zM1792 1280v-1280q0 -53 -37.5 -90.5t-90.5 -37.5h-1536q-53 0 -90.5 37.5t-37.5 90.5v1280 q0 53 37.5 90.5t90.5 37.5h1536q53 0 90.5 -37.5t37.5 -90.5z" /> <glyph glyph-name="key" unicode="" horiz-adv-x="1792" d="M832 1024q0 80 -56 136t-136 56t-136 -56t-56 -136q0 -42 19 -83q-41 19 -83 19q-80 0 -136 -56t-56 -136t56 -136t136 -56t136 56t56 136q0 42 -19 83q41 -19 83 -19q80 0 136 56t56 136zM1683 320q0 -17 -49 -66t-66 -49q-9 0 -28.5 16t-36.5 33t-38.5 40t-24.5 26 l-96 -96l220 -220q28 -28 28 -68q0 -42 -39 -81t-81 -39q-40 0 -68 28l-671 671q-176 -131 -365 -131q-163 0 -265.5 102.5t-102.5 265.5q0 160 95 313t248 248t313 95q163 0 265.5 -102.5t102.5 -265.5q0 -189 -131 -365l355 -355l96 96q-3 3 -26 24.5t-40 38.5t-33 36.5 t-16 28.5q0 17 49 66t66 49q13 0 23 -10q6 -6 46 -44.5t82 -79.5t86.5 -86t73 -78t28.5 -41z" /> <glyph glyph-name="cogs" unicode="" horiz-adv-x="1920" d="M896 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1664 128q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1152q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1280 731v-185q0 -10 -7 -19.5t-16 -10.5l-155 -24q-11 -35 -32 -76q34 -48 90 -115q7 -11 7 -20q0 -12 -7 -19q-23 -30 -82.5 -89.5t-78.5 -59.5q-11 0 -21 7l-115 90q-37 -19 -77 -31q-11 -108 -23 -155q-7 -24 -30 -24h-186q-11 0 -20 7.5t-10 17.5 l-23 153q-34 10 -75 31l-118 -89q-7 -7 -20 -7q-11 0 -21 8q-144 133 -144 160q0 9 7 19q10 14 41 53t47 61q-23 44 -35 82l-152 24q-10 1 -17 9.5t-7 19.5v185q0 10 7 19.5t16 10.5l155 24q11 35 32 76q-34 48 -90 115q-7 11 -7 20q0 12 7 20q22 30 82 89t79 59q11 0 21 -7 l115 -90q34 18 77 32q11 108 23 154q7 24 30 24h186q11 0 20 -7.5t10 -17.5l23 -153q34 -10 75 -31l118 89q8 7 20 7q11 0 21 -8q144 -133 144 -160q0 -8 -7 -19q-12 -16 -42 -54t-45 -60q23 -48 34 -82l152 -23q10 -2 17 -10.5t7 -19.5zM1920 198v-140q0 -16 -149 -31 q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20 t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31zM1920 1222v-140q0 -16 -149 -31q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68 q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70 q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31z" /> <glyph glyph-name="comments" unicode="" horiz-adv-x="1792" d="M1408 768q0 -139 -94 -257t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224 q0 139 94 257t256.5 186.5t353.5 68.5t353.5 -68.5t256.5 -186.5t94 -257zM1792 512q0 -120 -71 -224.5t-195 -176.5q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7 q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230z" /> <glyph glyph-name="thumbs_up_alt" unicode="" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 768q0 51 -39 89.5t-89 38.5h-352q0 58 48 159.5t48 160.5q0 98 -32 145t-128 47q-26 -26 -38 -85t-30.5 -125.5t-59.5 -109.5q-22 -23 -77 -91q-4 -5 -23 -30t-31.5 -41t-34.5 -42.5 t-40 -44t-38.5 -35.5t-40 -27t-35.5 -9h-32v-640h32q13 0 31.5 -3t33 -6.5t38 -11t35 -11.5t35.5 -12.5t29 -10.5q211 -73 342 -73h121q192 0 192 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5q32 1 53.5 47t21.5 81zM1536 769 q0 -89 -49 -163q9 -33 9 -69q0 -77 -38 -144q3 -21 3 -43q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5h-36h-93q-96 0 -189.5 22.5t-216.5 65.5q-116 40 -138 40h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h274q36 24 137 155q58 75 107 128 q24 25 35.5 85.5t30.5 126.5t62 108q39 37 90 37q84 0 151 -32.5t102 -101.5t35 -186q0 -93 -48 -192h176q104 0 180 -76t76 -179z" /> <glyph glyph-name="thumbs_down_alt" unicode="" d="M256 1088q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 512q0 35 -21.5 81t-53.5 47q15 17 25 47.5t10 55.5q0 69 -53 119q18 31 18 69q0 37 -17.5 73.5t-47.5 52.5q5 30 5 56q0 85 -49 126t-136 41h-128q-131 0 -342 -73q-5 -2 -29 -10.5 t-35.5 -12.5t-35 -11.5t-38 -11t-33 -6.5t-31.5 -3h-32v-640h32q16 0 35.5 -9t40 -27t38.5 -35.5t40 -44t34.5 -42.5t31.5 -41t23 -30q55 -68 77 -91q41 -43 59.5 -109.5t30.5 -125.5t38 -85q96 0 128 47t32 145q0 59 -48 160.5t-48 159.5h352q50 0 89 38.5t39 89.5z M1536 511q0 -103 -76 -179t-180 -76h-176q48 -99 48 -192q0 -118 -35 -186q-35 -69 -102 -101.5t-151 -32.5q-51 0 -90 37q-34 33 -54 82t-25.5 90.5t-17.5 84.5t-31 64q-48 50 -107 127q-101 131 -137 155h-274q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5 h288q22 0 138 40q128 44 223 66t200 22h112q140 0 226.5 -79t85.5 -216v-5q60 -77 60 -178q0 -22 -3 -43q38 -67 38 -144q0 -36 -9 -69q49 -73 49 -163z" /> <glyph glyph-name="star_half" unicode="" horiz-adv-x="896" d="M832 1504v-1339l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41z" /> <glyph glyph-name="heart_empty" unicode="" horiz-adv-x="1792" d="M1664 940q0 81 -21.5 143t-55 98.5t-81.5 59.5t-94 31t-98 8t-112 -25.5t-110.5 -64t-86.5 -72t-60 -61.5q-18 -22 -49 -22t-49 22q-24 28 -60 61.5t-86.5 72t-110.5 64t-112 25.5t-98 -8t-94 -31t-81.5 -59.5t-55 -98.5t-21.5 -143q0 -168 187 -355l581 -560l580 559 q188 188 188 356zM1792 940q0 -221 -229 -450l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5 q224 0 351 -124t127 -344z" /> <glyph glyph-name="signout" unicode="" horiz-adv-x="1664" d="M640 96q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h320q13 0 22.5 -9.5t9.5 -22.5q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-66 0 -113 -47t-47 -113v-704 q0 -66 47 -113t113 -47h288h11h13t11.5 -1t11.5 -3t8 -5.5t7 -9t2 -13.5zM1568 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45z" /> <glyph glyph-name="linkedin_sign" unicode="" d="M237 122h231v694h-231v-694zM483 1030q-1 52 -36 86t-93 34t-94.5 -34t-36.5 -86q0 -51 35.5 -85.5t92.5 -34.5h1q59 0 95 34.5t36 85.5zM1068 122h231v398q0 154 -73 233t-193 79q-136 0 -209 -117h2v101h-231q3 -66 0 -694h231v388q0 38 7 56q15 35 45 59.5t74 24.5 q116 0 116 -157v-371zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="pushpin" unicode="" horiz-adv-x="1152" d="M480 672v448q0 14 -9 23t-23 9t-23 -9t-9 -23v-448q0 -14 9 -23t23 -9t23 9t9 23zM1152 320q0 -26 -19 -45t-45 -19h-429l-51 -483q-2 -12 -10.5 -20.5t-20.5 -8.5h-1q-27 0 -32 27l-76 485h-404q-26 0 -45 19t-19 45q0 123 78.5 221.5t177.5 98.5v512q-52 0 -90 38 t-38 90t38 90t90 38h640q52 0 90 -38t38 -90t-38 -90t-90 -38v-512q99 0 177.5 -98.5t78.5 -221.5z" /> <glyph glyph-name="external_link" unicode="" horiz-adv-x="1792" d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" /> <glyph glyph-name="signin" unicode="" d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="trophy" unicode="" horiz-adv-x="1664" d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96 q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" /> <glyph glyph-name="github_sign" unicode="" d="M519 336q4 6 -3 13q-9 7 -14 2q-4 -6 3 -13q9 -7 14 -2zM491 377q-5 7 -12 4q-6 -4 0 -12q7 -8 12 -5q6 4 0 13zM450 417q2 4 -5 8q-7 2 -8 -2q-3 -5 4 -8q8 -2 9 2zM471 394q2 1 1.5 4.5t-3.5 5.5q-6 7 -10 3t1 -11q6 -6 11 -2zM557 319q2 7 -9 11q-9 3 -13 -4 q-2 -7 9 -11q9 -3 13 4zM599 316q0 8 -12 8q-10 0 -10 -8t11 -8t11 8zM638 323q-2 7 -13 5t-9 -9q2 -8 12 -6t10 10zM1280 640q0 212 -150 362t-362 150t-362 -150t-150 -362q0 -167 98 -300.5t252 -185.5q18 -3 26.5 5t8.5 20q0 52 -1 95q-6 -1 -15.5 -2.5t-35.5 -2t-48 4 t-43.5 20t-29.5 41.5q-23 59 -57 74q-2 1 -4.5 3.5l-8 8t-7 9.5t4 7.5t19.5 3.5q6 0 15 -2t30 -15.5t33 -35.5q16 -28 37.5 -42t43.5 -14t38 3.5t30 9.5q7 47 33 69q-49 6 -86 18.5t-73 39t-55.5 76t-19.5 119.5q0 79 53 137q-24 62 5 136q19 6 54.5 -7.5t60.5 -29.5l26 -16 q58 17 128 17t128 -17q11 7 28.5 18t55.5 26t57 9q29 -74 5 -136q53 -58 53 -137q0 -57 -14 -100.5t-35.5 -70t-53.5 -44.5t-62.5 -26t-68.5 -12q35 -31 35 -95q0 -40 -0.5 -89t-0.5 -51q0 -12 8.5 -20t26.5 -5q154 52 252 185.5t98 300.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="upload_alt" unicode="" horiz-adv-x="1664" d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" /> <glyph glyph-name="lemon" unicode="" d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44 q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5 q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -13 2 -25t3.5 -16.5t7.5 -20.5t8 -20q16 -40 25 -118.5t9 -136.5z" /> <glyph glyph-name="phone" unicode="" horiz-adv-x="1408" d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -53 3.5t-57.5 12.5t-47 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-127 79 -264 216t-216 264q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47t-12.5 57.5t-3.5 53q0 92 51 186 q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174q2 -1 19 -11.5t24 -14 t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" /> <glyph glyph-name="check_empty" unicode="" horiz-adv-x="1408" d="M1120 1280h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v832q0 66 -47 113t-113 47zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="bookmark_empty" unicode="" horiz-adv-x="1280" d="M1152 1280h-1024v-1242l423 406l89 85l89 -85l423 -406v1242zM1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289 q0 34 19.5 62t52.5 41q21 9 44 9h1048z" /> <glyph glyph-name="phone_sign" unicode="" d="M1280 343q0 11 -2 16t-18 16.5t-40.5 25t-47.5 26.5t-45.5 25t-28.5 15q-5 3 -19 13t-25 15t-21 5q-15 0 -36.5 -20.5t-39.5 -45t-38.5 -45t-33.5 -20.5q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170 126.5t-127 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5 t-3.5 16.5q0 13 20.5 33.5t45 38.5t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5 t320.5 -216.5q6 -2 30 -11t33 -12.5t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z " /> <glyph glyph-name="twitter" unicode="" horiz-adv-x="1664" d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" /> <glyph glyph-name="facebook" unicode="" horiz-adv-x="1024" d="M959 1524v-264h-157q-86 0 -116 -36t-30 -108v-189h293l-39 -296h-254v-759h-306v759h-255v296h255v218q0 186 104 288.5t277 102.5q147 0 228 -12z" /> <glyph glyph-name="github" unicode="" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -40 7t-13 30q0 3 0.5 76.5t0.5 134.5q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 119 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24 q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-85 13.5q-45 -113 -8 -204q-79 -87 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-39 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5 t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -88.5t0.5 -54.5q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103zM291 305q3 7 -7 12 q-10 3 -13 -2q-3 -7 7 -12q9 -6 13 2zM322 271q7 5 -2 16q-10 9 -16 3q-7 -5 2 -16q10 -10 16 -3zM352 226q9 7 0 19q-8 13 -17 6q-9 -5 0 -18t17 -7zM394 184q8 8 -4 19q-12 12 -20 3q-9 -8 4 -19q12 -12 20 -3zM451 159q3 11 -13 16q-15 4 -19 -7t13 -15q15 -6 19 6z M514 154q0 13 -17 11q-16 0 -16 -11q0 -13 17 -11q16 0 16 11zM572 164q-2 11 -18 9q-16 -3 -14 -15t18 -8t14 14z" /> <glyph glyph-name="unlock" unicode="" horiz-adv-x="1664" d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 t316.5 -131.5t131.5 -316.5z" /> <glyph glyph-name="credit_card" unicode="" horiz-adv-x="1920" d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" /> <glyph glyph-name="rss" unicode="" horiz-adv-x="1408" d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294 q187 -186 294 -425.5t120 -501.5z" /> <glyph glyph-name="hdd" unicode="" d="M1040 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1296 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1408 160v320q0 13 -9.5 22.5t-22.5 9.5 h-1216q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5zM178 640h1180l-157 482q-4 13 -16 21.5t-26 8.5h-782q-14 0 -26 -8.5t-16 -21.5zM1536 480v-320q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v320q0 25 16 75 l197 606q17 53 63 86t101 33h782q55 0 101 -33t63 -86l197 -606q16 -50 16 -75z" /> <glyph glyph-name="bullhorn" unicode="" horiz-adv-x="1792" d="M1664 896q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5v-384q0 -52 -38 -90t-90 -38q-417 347 -812 380q-58 -19 -91 -66t-31 -100.5t40 -92.5q-20 -33 -23 -65.5t6 -58t33.5 -55t48 -50t61.5 -50.5q-29 -58 -111.5 -83t-168.5 -11.5t-132 55.5q-7 23 -29.5 87.5 t-32 94.5t-23 89t-15 101t3.5 98.5t22 110.5h-122q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h480q435 0 896 384q52 0 90 -38t38 -90v-384zM1536 292v954q-394 -302 -768 -343v-270q377 -42 768 -341z" /> <glyph glyph-name="bell" unicode="" horiz-adv-x="1792" d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM246 128h1300q-266 300 -266 832q0 51 -24 105t-69 103t-121.5 80.5t-169.5 31.5t-169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -532 -266 -832z M1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5 t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" /> <glyph glyph-name="certificate" unicode="" d="M1376 640l138 -135q30 -28 20 -70q-12 -41 -52 -51l-188 -48l53 -186q12 -41 -19 -70q-29 -31 -70 -19l-186 53l-48 -188q-10 -40 -51 -52q-12 -2 -19 -2q-31 0 -51 22l-135 138l-135 -138q-28 -30 -70 -20q-41 11 -51 52l-48 188l-186 -53q-41 -12 -70 19q-31 29 -19 70 l53 186l-188 48q-40 10 -52 51q-10 42 20 70l138 135l-138 135q-30 28 -20 70q12 41 52 51l188 48l-53 186q-12 41 19 70q29 31 70 19l186 -53l48 188q10 41 51 51q41 12 70 -19l135 -139l135 139q29 30 70 19q41 -10 51 -51l48 -188l186 53q41 12 70 -19q31 -29 19 -70 l-53 -186l188 -48q40 -10 52 -51q10 -42 -20 -70z" /> <glyph glyph-name="hand_right" unicode="" horiz-adv-x="1792" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 768q0 51 -39 89.5t-89 38.5h-576q0 20 15 48.5t33 55t33 68t15 84.5q0 67 -44.5 97.5t-115.5 30.5q-24 0 -90 -139q-24 -44 -37 -65q-40 -64 -112 -145q-71 -81 -101 -106 q-69 -57 -140 -57h-32v-640h32q72 0 167 -32t193.5 -64t179.5 -32q189 0 189 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5h331q52 0 90 38t38 90zM1792 769q0 -105 -75.5 -181t-180.5 -76h-169q-4 -62 -37 -119q3 -21 3 -43 q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5q-133 0 -322 69q-164 59 -223 59h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h288q10 0 21.5 4.5t23.5 14t22.5 18t24 22.5t20.5 21.5t19 21.5t14 17q65 74 100 129q13 21 33 62t37 72t40.5 63t55 49.5 t69.5 17.5q125 0 206.5 -67t81.5 -189q0 -68 -22 -128h374q104 0 180 -76t76 -179z" /> <glyph glyph-name="hand_left" unicode="" horiz-adv-x="1792" d="M1376 128h32v640h-32q-35 0 -67.5 12t-62.5 37t-50 46t-49 54q-8 9 -12 14q-72 81 -112 145q-14 22 -38 68q-1 3 -10.5 22.5t-18.5 36t-20 35.5t-21.5 30.5t-18.5 11.5q-71 0 -115.5 -30.5t-44.5 -97.5q0 -43 15 -84.5t33 -68t33 -55t15 -48.5h-576q-50 0 -89 -38.5 t-39 -89.5q0 -52 38 -90t90 -38h331q-15 -17 -25 -47.5t-10 -55.5q0 -69 53 -119q-18 -32 -18 -69t17.5 -73.5t47.5 -52.5q-4 -24 -4 -56q0 -85 48.5 -126t135.5 -41q84 0 183 32t194 64t167 32zM1664 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45z M1792 768v-640q0 -53 -37.5 -90.5t-90.5 -37.5h-288q-59 0 -223 -59q-190 -69 -317 -69q-142 0 -230 77.5t-87 217.5l1 5q-61 76 -61 178q0 22 3 43q-33 57 -37 119h-169q-105 0 -180.5 76t-75.5 181q0 103 76 179t180 76h374q-22 60 -22 128q0 122 81.5 189t206.5 67 q38 0 69.5 -17.5t55 -49.5t40.5 -63t37 -72t33 -62q35 -55 100 -129q2 -3 14 -17t19 -21.5t20.5 -21.5t24 -22.5t22.5 -18t23.5 -14t21.5 -4.5h288q53 0 90.5 -37.5t37.5 -90.5z" /> <glyph glyph-name="hand_up" unicode="" d="M1280 -64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 700q0 189 -167 189q-26 0 -56 -5q-16 30 -52.5 47.5t-73.5 17.5t-69 -18q-50 53 -119 53q-25 0 -55.5 -10t-47.5 -25v331q0 52 -38 90t-90 38q-51 0 -89.5 -39t-38.5 -89v-576 q-20 0 -48.5 15t-55 33t-68 33t-84.5 15q-67 0 -97.5 -44.5t-30.5 -115.5q0 -24 139 -90q44 -24 65 -37q64 -40 145 -112q81 -71 106 -101q57 -69 57 -140v-32h640v32q0 72 32 167t64 193.5t32 179.5zM1536 705q0 -133 -69 -322q-59 -164 -59 -223v-288q0 -53 -37.5 -90.5 t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5v288q0 10 -4.5 21.5t-14 23.5t-18 22.5t-22.5 24t-21.5 20.5t-21.5 19t-17 14q-74 65 -129 100q-21 13 -62 33t-72 37t-63 40.5t-49.5 55t-17.5 69.5q0 125 67 206.5t189 81.5q68 0 128 -22v374q0 104 76 180t179 76 q105 0 181 -75.5t76 -180.5v-169q62 -4 119 -37q21 3 43 3q101 0 178 -60q139 1 219.5 -85t80.5 -227z" /> <glyph glyph-name="hand_down" unicode="" d="M1408 576q0 84 -32 183t-64 194t-32 167v32h-640v-32q0 -35 -12 -67.5t-37 -62.5t-46 -50t-54 -49q-9 -8 -14 -12q-81 -72 -145 -112q-22 -14 -68 -38q-3 -1 -22.5 -10.5t-36 -18.5t-35.5 -20t-30.5 -21.5t-11.5 -18.5q0 -71 30.5 -115.5t97.5 -44.5q43 0 84.5 15t68 33 t55 33t48.5 15v-576q0 -50 38.5 -89t89.5 -39q52 0 90 38t38 90v331q46 -35 103 -35q69 0 119 53q32 -18 69 -18t73.5 17.5t52.5 47.5q24 -4 56 -4q85 0 126 48.5t41 135.5zM1280 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 580 q0 -142 -77.5 -230t-217.5 -87l-5 1q-76 -61 -178 -61q-22 0 -43 3q-54 -30 -119 -37v-169q0 -105 -76 -180.5t-181 -75.5q-103 0 -179 76t-76 180v374q-54 -22 -128 -22q-121 0 -188.5 81.5t-67.5 206.5q0 38 17.5 69.5t49.5 55t63 40.5t72 37t62 33q55 35 129 100 q3 2 17 14t21.5 19t21.5 20.5t22.5 24t18 22.5t14 23.5t4.5 21.5v288q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-288q0 -59 59 -223q69 -190 69 -317z" /> <glyph glyph-name="circle_arrow_left" unicode="" d="M1280 576v128q0 26 -19 45t-45 19h-502l189 189q19 19 19 45t-19 45l-91 91q-18 18 -45 18t-45 -18l-362 -362l-91 -91q-18 -18 -18 -45t18 -45l91 -91l362 -362q18 -18 45 -18t45 18l91 91q18 18 18 45t-18 45l-189 189h502q26 0 45 19t19 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="circle_arrow_right" unicode="" d="M1285 640q0 27 -18 45l-91 91l-362 362q-18 18 -45 18t-45 -18l-91 -91q-18 -18 -18 -45t18 -45l189 -189h-502q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h502l-189 -189q-19 -19 -19 -45t19 -45l91 -91q18 -18 45 -18t45 18l362 362l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="circle_arrow_up" unicode="" d="M1284 641q0 27 -18 45l-362 362l-91 91q-18 18 -45 18t-45 -18l-91 -91l-362 -362q-18 -18 -18 -45t18 -45l91 -91q18 -18 45 -18t45 18l189 189v-502q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v502l189 -189q19 -19 45 -19t45 19l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="circle_arrow_down" unicode="" d="M1284 639q0 27 -18 45l-91 91q-18 18 -45 18t-45 -18l-189 -189v502q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-502l-189 189q-19 19 -45 19t-45 -19l-91 -91q-18 -18 -18 -45t18 -45l362 -362l91 -91q18 -18 45 -18t45 18l91 91l362 362q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="globe" unicode="" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1042 887q-2 -1 -9.5 -9.5t-13.5 -9.5q2 0 4.5 5t5 11t3.5 7q6 7 22 15q14 6 52 12q34 8 51 -11 q-2 2 9.5 13t14.5 12q3 2 15 4.5t15 7.5l2 22q-12 -1 -17.5 7t-6.5 21q0 -2 -6 -8q0 7 -4.5 8t-11.5 -1t-9 -1q-10 3 -15 7.5t-8 16.5t-4 15q-2 5 -9.5 11t-9.5 10q-1 2 -2.5 5.5t-3 6.5t-4 5.5t-5.5 2.5t-7 -5t-7.5 -10t-4.5 -5q-3 2 -6 1.5t-4.5 -1t-4.5 -3t-5 -3.5 q-3 -2 -8.5 -3t-8.5 -2q15 5 -1 11q-10 4 -16 3q9 4 7.5 12t-8.5 14h5q-1 4 -8.5 8.5t-17.5 8.5t-13 6q-8 5 -34 9.5t-33 0.5q-5 -6 -4.5 -10.5t4 -14t3.5 -12.5q1 -6 -5.5 -13t-6.5 -12q0 -7 14 -15.5t10 -21.5q-3 -8 -16 -16t-16 -12q-5 -8 -1.5 -18.5t10.5 -16.5 q2 -2 1.5 -4t-3.5 -4.5t-5.5 -4t-6.5 -3.5l-3 -2q-11 -5 -20.5 6t-13.5 26q-7 25 -16 30q-23 8 -29 -1q-5 13 -41 26q-25 9 -58 4q6 1 0 15q-7 15 -19 12q3 6 4 17.5t1 13.5q3 13 12 23q1 1 7 8.5t9.5 13.5t0.5 6q35 -4 50 11q5 5 11.5 17t10.5 17q9 6 14 5.5t14.5 -5.5 t14.5 -5q14 -1 15.5 11t-7.5 20q12 -1 3 17q-4 7 -8 9q-12 4 -27 -5q-8 -4 2 -8q-1 1 -9.5 -10.5t-16.5 -17.5t-16 5q-1 1 -5.5 13.5t-9.5 13.5q-8 0 -16 -15q3 8 -11 15t-24 8q19 12 -8 27q-7 4 -20.5 5t-19.5 -4q-5 -7 -5.5 -11.5t5 -8t10.5 -5.5t11.5 -4t8.5 -3 q14 -10 8 -14q-2 -1 -8.5 -3.5t-11.5 -4.5t-6 -4q-3 -4 0 -14t-2 -14q-5 5 -9 17.5t-7 16.5q7 -9 -25 -6l-10 1q-4 0 -16 -2t-20.5 -1t-13.5 8q-4 8 0 20q1 4 4 2q-4 3 -11 9.5t-10 8.5q-46 -15 -94 -41q6 -1 12 1q5 2 13 6.5t10 5.5q34 14 42 7l5 5q14 -16 20 -25 q-7 4 -30 1q-20 -6 -22 -12q7 -12 5 -18q-4 3 -11.5 10t-14.5 11t-15 5q-16 0 -22 -1q-146 -80 -235 -222q7 -7 12 -8q4 -1 5 -9t2.5 -11t11.5 3q9 -8 3 -19q1 1 44 -27q19 -17 21 -21q3 -11 -10 -18q-1 2 -9 9t-9 4q-3 -5 0.5 -18.5t10.5 -12.5q-7 0 -9.5 -16t-2.5 -35.5 t-1 -23.5l2 -1q-3 -12 5.5 -34.5t21.5 -19.5q-13 -3 20 -43q6 -8 8 -9q3 -2 12 -7.5t15 -10t10 -10.5q4 -5 10 -22.5t14 -23.5q-2 -6 9.5 -20t10.5 -23q-1 0 -2.5 -1t-2.5 -1q3 -7 15.5 -14t15.5 -13q1 -3 2 -10t3 -11t8 -2q2 20 -24 62q-15 25 -17 29q-3 5 -5.5 15.5 t-4.5 14.5q2 0 6 -1.5t8.5 -3.5t7.5 -4t2 -3q-3 -7 2 -17.5t12 -18.5t17 -19t12 -13q6 -6 14 -19.5t0 -13.5q9 0 20 -10.5t17 -19.5q5 -8 8 -26t5 -24q2 -7 8.5 -13.5t12.5 -9.5l16 -8t13 -7q5 -2 18.5 -10.5t21.5 -11.5q10 -4 16 -4t14.5 2.5t13.5 3.5q15 2 29 -15t21 -21 q36 -19 55 -11q-2 -1 0.5 -7.5t8 -15.5t9 -14.5t5.5 -8.5q5 -6 18 -15t18 -15q6 4 7 9q-3 -8 7 -20t18 -10q14 3 14 32q-31 -15 -49 18q0 1 -2.5 5.5t-4 8.5t-2.5 8.5t0 7.5t5 3q9 0 10 3.5t-2 12.5t-4 13q-1 8 -11 20t-12 15q-5 -9 -16 -8t-16 9q0 -1 -1.5 -5.5t-1.5 -6.5 q-13 0 -15 1q1 3 2.5 17.5t3.5 22.5q1 4 5.5 12t7.5 14.5t4 12.5t-4.5 9.5t-17.5 2.5q-19 -1 -26 -20q-1 -3 -3 -10.5t-5 -11.5t-9 -7q-7 -3 -24 -2t-24 5q-13 8 -22.5 29t-9.5 37q0 10 2.5 26.5t3 25t-5.5 24.5q3 2 9 9.5t10 10.5q2 1 4.5 1.5t4.5 0t4 1.5t3 6q-1 1 -4 3 q-3 3 -4 3q7 -3 28.5 1.5t27.5 -1.5q15 -11 22 2q0 1 -2.5 9.5t-0.5 13.5q5 -27 29 -9q3 -3 15.5 -5t17.5 -5q3 -2 7 -5.5t5.5 -4.5t5 0.5t8.5 6.5q10 -14 12 -24q11 -40 19 -44q7 -3 11 -2t4.5 9.5t0 14t-1.5 12.5l-1 8v18l-1 8q-15 3 -18.5 12t1.5 18.5t15 18.5q1 1 8 3.5 t15.5 6.5t12.5 8q21 19 15 35q7 0 11 9q-1 0 -5 3t-7.5 5t-4.5 2q9 5 2 16q5 3 7.5 11t7.5 10q9 -12 21 -2q8 8 1 16q5 7 20.5 10.5t18.5 9.5q7 -2 8 2t1 12t3 12q4 5 15 9t13 5l17 11q3 4 0 4q18 -2 31 11q10 11 -6 20q3 6 -3 9.5t-15 5.5q3 1 11.5 0.5t10.5 1.5 q15 10 -7 16q-17 5 -43 -12zM879 10q206 36 351 189q-3 3 -12.5 4.5t-12.5 3.5q-18 7 -24 8q1 7 -2.5 13t-8 9t-12.5 8t-11 7q-2 2 -7 6t-7 5.5t-7.5 4.5t-8.5 2t-10 -1l-3 -1q-3 -1 -5.5 -2.5t-5.5 -3t-4 -3t0 -2.5q-21 17 -36 22q-5 1 -11 5.5t-10.5 7t-10 1.5t-11.5 -7 q-5 -5 -6 -15t-2 -13q-7 5 0 17.5t2 18.5q-3 6 -10.5 4.5t-12 -4.5t-11.5 -8.5t-9 -6.5t-8.5 -5.5t-8.5 -7.5q-3 -4 -6 -12t-5 -11q-2 4 -11.5 6.5t-9.5 5.5q2 -10 4 -35t5 -38q7 -31 -12 -48q-27 -25 -29 -40q-4 -22 12 -26q0 -7 -8 -20.5t-7 -21.5q0 -6 2 -16z" /> <glyph glyph-name="wrench" unicode="" horiz-adv-x="1664" d="M384 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1028 484l-682 -682q-37 -37 -90 -37q-52 0 -91 37l-106 108q-38 36 -38 90q0 53 38 91l681 681q39 -98 114.5 -173.5t173.5 -114.5zM1662 919q0 -39 -23 -106q-47 -134 -164.5 -217.5 t-258.5 -83.5q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q58 0 121.5 -16.5t107.5 -46.5q16 -11 16 -28t-16 -28l-293 -169v-224l193 -107q5 3 79 48.5t135.5 81t70.5 35.5q15 0 23.5 -10t8.5 -25z" /> <glyph glyph-name="tasks" unicode="" horiz-adv-x="1792" d="M1024 128h640v128h-640v-128zM640 640h1024v128h-1024v-128zM1280 1152h384v128h-384v-128zM1792 320v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 832v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19 t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" /> <glyph glyph-name="filter" unicode="" horiz-adv-x="1408" d="M1403 1241q17 -41 -14 -70l-493 -493v-742q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-256 256q-19 19 -19 45v486l-493 493q-31 29 -14 70q17 39 59 39h1280q42 0 59 -39z" /> <glyph glyph-name="briefcase" unicode="" horiz-adv-x="1792" d="M640 1280h512v128h-512v-128zM1792 640v-480q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v480h672v-160q0 -26 19 -45t45 -19h320q26 0 45 19t19 45v160h672zM1024 640v-128h-256v128h256zM1792 1120v-384h-1792v384q0 66 47 113t113 47h352v160q0 40 28 68 t68 28h576q40 0 68 -28t28 -68v-160h352q66 0 113 -47t47 -113z" /> <glyph glyph-name="fullscreen" unicode="" d="M1283 995l-355 -355l355 -355l144 144q29 31 70 14q39 -17 39 -59v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l144 144l-355 355l-355 -355l144 -144q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l144 -144 l355 355l-355 355l-144 -144q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v448q0 26 19 45t45 19h448q42 0 59 -40q17 -39 -14 -69l-144 -144l355 -355l355 355l-144 144q-31 30 -14 69q17 40 59 40h448q26 0 45 -19t19 -45v-448q0 -42 -39 -59q-13 -5 -25 -5q-26 0 -45 19z " /> <glyph glyph-name="group" unicode="" horiz-adv-x="1920" d="M593 640q-162 -5 -265 -128h-134q-82 0 -138 40.5t-56 118.5q0 353 124 353q6 0 43.5 -21t97.5 -42.5t119 -21.5q67 0 133 23q-5 -37 -5 -66q0 -139 81 -256zM1664 3q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q10 0 43 -21.5t73 -48t107 -48t135 -21.5t135 21.5t107 48t73 48t43 21.5q61 0 111.5 -20t85.5 -53.5t62 -81t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM640 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75 t75 -181zM1344 896q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5zM1920 671q0 -78 -56 -118.5t-138 -40.5h-134q-103 123 -265 128q81 117 81 256q0 29 -5 66q66 -23 133 -23q59 0 119 21.5t97.5 42.5 t43.5 21q124 0 124 -353zM1792 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181z" /> <glyph glyph-name="link" unicode="" horiz-adv-x="1664" d="M1456 320q0 40 -28 68l-208 208q-28 28 -68 28q-42 0 -72 -32q3 -3 19 -18.5t21.5 -21.5t15 -19t13 -25.5t3.5 -27.5q0 -40 -28 -68t-68 -28q-15 0 -27.5 3.5t-25.5 13t-19 15t-21.5 21.5t-18.5 19q-33 -31 -33 -73q0 -40 28 -68l206 -207q27 -27 68 -27q40 0 68 26 l147 146q28 28 28 67zM753 1025q0 40 -28 68l-206 207q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l208 -208q27 -27 68 -27q42 0 72 31q-3 3 -19 18.5t-21.5 21.5t-15 19t-13 25.5t-3.5 27.5q0 40 28 68t68 28q15 0 27.5 -3.5t25.5 -13t19 -15 t21.5 -21.5t18.5 -19q33 31 33 73zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-206 207q-83 83 -83 203q0 123 88 209l-88 88q-86 -88 -208 -88q-120 0 -204 84l-208 208q-84 84 -84 204t85 203l147 146q83 83 203 83q121 0 204 -85l206 -207 q83 -83 83 -203q0 -123 -88 -209l88 -88q86 88 208 88q120 0 204 -84l208 -208q84 -84 84 -204z" /> <glyph glyph-name="cloud" unicode="" horiz-adv-x="1920" d="M1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088q-185 0 -316.5 131.5t-131.5 316.5q0 132 71 241.5t187 163.5q-2 28 -2 43q0 212 150 362t362 150q158 0 286.5 -88t187.5 -230q70 62 166 62q106 0 181 -75t75 -181q0 -75 -41 -138q129 -30 213 -134.5t84 -239.5z " /> <glyph glyph-name="beaker" unicode="" horiz-adv-x="1664" d="M1527 88q56 -89 21.5 -152.5t-140.5 -63.5h-1152q-106 0 -140.5 63.5t21.5 152.5l503 793v399h-64q-26 0 -45 19t-19 45t19 45t45 19h512q26 0 45 -19t19 -45t-19 -45t-45 -19h-64v-399zM748 813l-272 -429h712l-272 429l-20 31v37v399h-128v-399v-37z" /> <glyph glyph-name="cut" unicode="" horiz-adv-x="1792" d="M960 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1260 576l507 -398q28 -20 25 -56q-5 -35 -35 -51l-128 -64q-13 -7 -29 -7q-17 0 -31 8l-690 387l-110 -66q-8 -4 -12 -5q14 -49 10 -97q-7 -77 -56 -147.5t-132 -123.5q-132 -84 -277 -84 q-136 0 -222 78q-90 84 -79 207q7 76 56 147t131 124q132 84 278 84q83 0 151 -31q9 13 22 22l122 73l-122 73q-13 9 -22 22q-68 -31 -151 -31q-146 0 -278 84q-82 53 -131 124t-56 147q-5 59 15.5 113t63.5 93q85 79 222 79q145 0 277 -84q83 -52 132 -123t56 -148 q4 -48 -10 -97q4 -1 12 -5l110 -66l690 387q14 8 31 8q16 0 29 -7l128 -64q30 -16 35 -51q3 -36 -25 -56zM579 836q46 42 21 108t-106 117q-92 59 -192 59q-74 0 -113 -36q-46 -42 -21 -108t106 -117q92 -59 192 -59q74 0 113 36zM494 91q81 51 106 117t-21 108 q-39 36 -113 36q-100 0 -192 -59q-81 -51 -106 -117t21 -108q39 -36 113 -36q100 0 192 59zM672 704l96 -58v11q0 36 33 56l14 8l-79 47l-26 -26q-3 -3 -10 -11t-12 -12q-2 -2 -4 -3.5t-3 -2.5zM896 480l96 -32l736 576l-128 64l-768 -431v-113l-160 -96l9 -8q2 -2 7 -6 q4 -4 11 -12t11 -12l26 -26zM1600 64l128 64l-520 408l-177 -138q-2 -3 -13 -7z" /> <glyph glyph-name="copy" unicode="" horiz-adv-x="1792" d="M1696 1152q40 0 68 -28t28 -68v-1216q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v288h-544q-40 0 -68 28t-28 68v672q0 40 20 88t48 76l408 408q28 28 76 48t88 20h416q40 0 68 -28t28 -68v-328q68 40 128 40h416zM1152 939l-299 -299h299v299zM512 1323l-299 -299 h299v299zM708 676l316 316v416h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h512v256q0 40 20 88t48 76zM1664 -128v1152h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h896z" /> <glyph glyph-name="paper_clip" unicode="" horiz-adv-x="1408" d="M1404 151q0 -117 -79 -196t-196 -79q-135 0 -235 100l-777 776q-113 115 -113 271q0 159 110 270t269 111q158 0 273 -113l605 -606q10 -10 10 -22q0 -16 -30.5 -46.5t-46.5 -30.5q-13 0 -23 10l-606 607q-79 77 -181 77q-106 0 -179 -75t-73 -181q0 -105 76 -181 l776 -777q63 -63 145 -63q64 0 106 42t42 106q0 82 -63 145l-581 581q-26 24 -60 24q-29 0 -48 -19t-19 -48q0 -32 25 -59l410 -410q10 -10 10 -22q0 -16 -31 -47t-47 -31q-12 0 -22 10l-410 410q-63 61 -63 149q0 82 57 139t139 57q88 0 149 -63l581 -581q100 -98 100 -235 z" /> <glyph glyph-name="save" unicode="" d="M384 0h768v384h-768v-384zM1280 0h128v896q0 14 -10 38.5t-20 34.5l-281 281q-10 10 -34 20t-39 10v-416q0 -40 -28 -68t-68 -28h-576q-40 0 -68 28t-28 68v416h-128v-1280h128v416q0 40 28 68t68 28h832q40 0 68 -28t28 -68v-416zM896 928v320q0 13 -9.5 22.5t-22.5 9.5 h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5zM1536 896v-928q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h928q40 0 88 -20t76 -48l280 -280q28 -28 48 -76t20 -88z" /> <glyph glyph-name="sign_blank" unicode="" d="M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="reorder" unicode="" d="M1536 192v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 704v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 1216v-128q0 -26 -19 -45 t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" /> <glyph glyph-name="ul" unicode="" horiz-adv-x="1792" d="M384 128q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 640q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1152q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z M1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" /> <glyph glyph-name="ol" unicode="" horiz-adv-x="1792" d="M381 -84q0 -80 -54.5 -126t-135.5 -46q-106 0 -172 66l57 88q49 -45 106 -45q29 0 50.5 14.5t21.5 42.5q0 64 -105 56l-26 56q8 10 32.5 43.5t42.5 54t37 38.5v1q-16 0 -48.5 -1t-48.5 -1v-53h-106v152h333v-88l-95 -115q51 -12 81 -49t30 -88zM383 543v-159h-362 q-6 36 -6 54q0 51 23.5 93t56.5 68t66 47.5t56.5 43.5t23.5 45q0 25 -14.5 38.5t-39.5 13.5q-46 0 -81 -58l-85 59q24 51 71.5 79.5t105.5 28.5q73 0 123 -41.5t50 -112.5q0 -50 -34 -91.5t-75 -64.5t-75.5 -50.5t-35.5 -52.5h127v60h105zM1792 224v-192q0 -13 -9.5 -22.5 t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1123v-99h-335v99h107q0 41 0.5 121.5t0.5 121.5v12h-2q-8 -17 -50 -54l-71 76l136 127h106v-404h108zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216 q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" /> <glyph glyph-name="strikethrough" unicode="" horiz-adv-x="1792" d="M1760 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h1728zM483 704q-28 35 -51 80q-48 98 -48 188q0 181 134 309q133 127 393 127q50 0 167 -19q66 -12 177 -48q10 -38 21 -118q14 -123 14 -183q0 -18 -5 -45l-12 -3l-84 6 l-14 2q-50 149 -103 205q-88 91 -210 91q-114 0 -182 -59q-67 -58 -67 -146q0 -73 66 -140t279 -129q69 -20 173 -66q58 -28 95 -52h-743zM990 448h411q7 -39 7 -92q0 -111 -41 -212q-23 -56 -71 -104q-37 -35 -109 -81q-80 -48 -153 -66q-80 -21 -203 -21q-114 0 -195 23 l-140 40q-57 16 -72 28q-8 8 -8 22v13q0 108 -2 156q-1 30 0 68l2 37v44l102 2q15 -34 30 -71t22.5 -56t12.5 -27q35 -57 80 -94q43 -36 105 -57q59 -22 132 -22q64 0 139 27q77 26 122 86q47 61 47 129q0 84 -81 157q-34 29 -137 71z" /> <glyph glyph-name="underline" unicode="" d="M48 1313q-37 2 -45 4l-3 88q13 1 40 1q60 0 112 -4q132 -7 166 -7q86 0 168 3q116 4 146 5q56 0 86 2l-1 -14l2 -64v-9q-60 -9 -124 -9q-60 0 -79 -25q-13 -14 -13 -132q0 -13 0.5 -32.5t0.5 -25.5l1 -229l14 -280q6 -124 51 -202q35 -59 96 -92q88 -47 177 -47 q104 0 191 28q56 18 99 51q48 36 65 64q36 56 53 114q21 73 21 229q0 79 -3.5 128t-11 122.5t-13.5 159.5l-4 59q-5 67 -24 88q-34 35 -77 34l-100 -2l-14 3l2 86h84l205 -10q76 -3 196 10l18 -2q6 -38 6 -51q0 -7 -4 -31q-45 -12 -84 -13q-73 -11 -79 -17q-15 -15 -15 -41 q0 -7 1.5 -27t1.5 -31q8 -19 22 -396q6 -195 -15 -304q-15 -76 -41 -122q-38 -65 -112 -123q-75 -57 -182 -89q-109 -33 -255 -33q-167 0 -284 46q-119 47 -179 122q-61 76 -83 195q-16 80 -16 237v333q0 188 -17 213q-25 36 -147 39zM1536 -96v64q0 14 -9 23t-23 9h-1472 q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h1472q14 0 23 9t9 23z" /> <glyph glyph-name="table" unicode="" horiz-adv-x="1664" d="M512 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23 v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 160v192 q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192 q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1664 1248v-1088q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1344q66 0 113 -47t47 -113 z" /> <glyph glyph-name="magic" unicode="" horiz-adv-x="1664" d="M1190 955l293 293l-107 107l-293 -293zM1637 1248q0 -27 -18 -45l-1286 -1286q-18 -18 -45 -18t-45 18l-198 198q-18 18 -18 45t18 45l1286 1286q18 18 45 18t45 -18l198 -198q18 -18 18 -45zM286 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM636 1276 l196 -60l-196 -60l-60 -196l-60 196l-196 60l196 60l60 196zM1566 798l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM926 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98z" /> <glyph glyph-name="truck" unicode="" horiz-adv-x="1792" d="M640 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM256 640h384v256h-158q-13 0 -22 -9l-195 -195q-9 -9 -9 -22v-30zM1536 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1792 1216v-1024q0 -15 -4 -26.5t-13.5 -18.5 t-16.5 -11.5t-23.5 -6t-22.5 -2t-25.5 0t-22.5 0.5q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-64q-3 0 -22.5 -0.5t-25.5 0t-22.5 2t-23.5 6t-16.5 11.5t-13.5 18.5t-4 26.5q0 26 19 45t45 19v320q0 8 -0.5 35t0 38 t2.5 34.5t6.5 37t14 30.5t22.5 30l198 198q19 19 50.5 32t58.5 13h160v192q0 26 19 45t45 19h1024q26 0 45 -19t19 -45z" /> <glyph glyph-name="pinterest" unicode="" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103q-111 0 -218 32q59 93 78 164q9 34 54 211q20 -39 73 -67.5t114 -28.5q121 0 216 68.5t147 188.5t52 270q0 114 -59.5 214t-172.5 163t-255 63q-105 0 -196 -29t-154.5 -77t-109 -110.5t-67 -129.5t-21.5 -134 q0 -104 40 -183t117 -111q30 -12 38 20q2 7 8 31t8 30q6 23 -11 43q-51 61 -51 151q0 151 104.5 259.5t273.5 108.5q151 0 235.5 -82t84.5 -213q0 -170 -68.5 -289t-175.5 -119q-61 0 -98 43.5t-23 104.5q8 35 26.5 93.5t30 103t11.5 75.5q0 50 -27 83t-77 33 q-62 0 -105 -57t-43 -142q0 -73 25 -122l-99 -418q-17 -70 -13 -177q-206 91 -333 281t-127 423q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="pinterest_sign" unicode="" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-725q85 122 108 210q9 34 53 209q21 -39 73.5 -67t112.5 -28q181 0 295.5 147.5t114.5 373.5q0 84 -35 162.5t-96.5 139t-152.5 97t-197 36.5q-104 0 -194.5 -28.5t-153 -76.5 t-107.5 -109.5t-66.5 -128t-21.5 -132.5q0 -102 39.5 -180t116.5 -110q13 -5 23.5 0t14.5 19q10 44 15 61q6 23 -11 42q-50 62 -50 150q0 150 103.5 256.5t270.5 106.5q149 0 232.5 -81t83.5 -210q0 -168 -67.5 -286t-173.5 -118q-60 0 -97 43.5t-23 103.5q8 34 26.5 92.5 t29.5 102t11 74.5q0 49 -26.5 81.5t-75.5 32.5q-61 0 -103.5 -56.5t-42.5 -139.5q0 -72 24 -121l-98 -414q-24 -100 -7 -254h-183q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960z" /> <glyph glyph-name="google_plus_sign" unicode="" d="M917 631q0 26 -6 64h-362v-132h217q-3 -24 -16.5 -50t-37.5 -53t-66.5 -44.5t-96.5 -17.5q-99 0 -169 71t-70 171t70 171t169 71q92 0 153 -59l104 101q-108 100 -257 100q-160 0 -272 -112.5t-112 -271.5t112 -271.5t272 -112.5q165 0 266.5 105t101.5 270zM1262 585 h109v110h-109v110h-110v-110h-110v-110h110v-110h110v110zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="google_plus" unicode="" horiz-adv-x="2304" d="M1437 623q0 -208 -87 -370.5t-248 -254t-369 -91.5q-149 0 -285 58t-234 156t-156 234t-58 285t58 285t156 234t234 156t285 58q286 0 491 -192l-199 -191q-117 113 -292 113q-123 0 -227.5 -62t-165.5 -168.5t-61 -232.5t61 -232.5t165.5 -168.5t227.5 -62 q83 0 152.5 23t114.5 57.5t78.5 78.5t49 83t21.5 74h-416v252h692q12 -63 12 -122zM2304 745v-210h-209v-209h-210v209h-209v210h209v209h210v-209h209z" /> <glyph glyph-name="money" unicode="" horiz-adv-x="1920" d="M768 384h384v96h-128v448h-114l-148 -137l77 -80q42 37 55 57h2v-288h-128v-96zM1280 640q0 -70 -21 -142t-59.5 -134t-101.5 -101t-138 -39t-138 39t-101.5 101t-59.5 134t-21 142t21 142t59.5 134t101.5 101t138 39t138 -39t101.5 -101t59.5 -134t21 -142zM1792 384 v512q-106 0 -181 75t-75 181h-1152q0 -106 -75 -181t-181 -75v-512q106 0 181 -75t75 -181h1152q0 106 75 181t181 75zM1920 1216v-1152q0 -26 -19 -45t-45 -19h-1792q-26 0 -45 19t-19 45v1152q0 26 19 45t45 19h1792q26 0 45 -19t19 -45z" /> <glyph glyph-name="caret_down" unicode="" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" /> <glyph glyph-name="caret_up" unicode="" horiz-adv-x="1024" d="M1024 320q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" /> <glyph glyph-name="caret_left" unicode="" horiz-adv-x="640" d="M640 1088v-896q0 -26 -19 -45t-45 -19t-45 19l-448 448q-19 19 -19 45t19 45l448 448q19 19 45 19t45 -19t19 -45z" /> <glyph glyph-name="caret_right" unicode="" horiz-adv-x="640" d="M576 640q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19t-19 45v896q0 26 19 45t45 19t45 -19l448 -448q19 -19 19 -45z" /> <glyph glyph-name="columns" unicode="" horiz-adv-x="1664" d="M160 0h608v1152h-640v-1120q0 -13 9.5 -22.5t22.5 -9.5zM1536 32v1120h-640v-1152h608q13 0 22.5 9.5t9.5 22.5zM1664 1248v-1216q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1344q66 0 113 -47t47 -113z" /> <glyph glyph-name="sort" unicode="" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45zM1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" /> <glyph glyph-name="sort_down" unicode="" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" /> <glyph glyph-name="sort_up" unicode="" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" /> <glyph glyph-name="envelope_alt" unicode="" horiz-adv-x="1792" d="M1792 826v-794q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v794q44 -49 101 -87q362 -246 497 -345q57 -42 92.5 -65.5t94.5 -48t110 -24.5h1h1q51 0 110 24.5t94.5 48t92.5 65.5q170 123 498 345q57 39 100 87zM1792 1120q0 -79 -49 -151t-122 -123 q-376 -261 -468 -325q-10 -7 -42.5 -30.5t-54 -38t-52 -32.5t-57.5 -27t-50 -9h-1h-1q-23 0 -50 9t-57.5 27t-52 32.5t-54 38t-42.5 30.5q-91 64 -262 182.5t-205 142.5q-62 42 -117 115.5t-55 136.5q0 78 41.5 130t118.5 52h1472q65 0 112.5 -47t47.5 -113z" /> <glyph glyph-name="linkedin" unicode="" d="M349 911v-991h-330v991h330zM370 1217q1 -73 -50.5 -122t-135.5 -49h-2q-82 0 -132 49t-50 122q0 74 51.5 122.5t134.5 48.5t133 -48.5t51 -122.5zM1536 488v-568h-329v530q0 105 -40.5 164.5t-126.5 59.5q-63 0 -105.5 -34.5t-63.5 -85.5q-11 -30 -11 -81v-553h-329 q2 399 2 647t-1 296l-1 48h329v-144h-2q20 32 41 56t56.5 52t87 43.5t114.5 15.5q171 0 275 -113.5t104 -332.5z" /> <glyph glyph-name="undo" unicode="" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298z" /> <glyph glyph-name="legal" unicode="" horiz-adv-x="1792" d="M1771 0q0 -53 -37 -90l-107 -108q-39 -37 -91 -37q-53 0 -90 37l-363 364q-38 36 -38 90q0 53 43 96l-256 256l-126 -126q-14 -14 -34 -14t-34 14q2 -2 12.5 -12t12.5 -13t10 -11.5t10 -13.5t6 -13.5t5.5 -16.5t1.5 -18q0 -38 -28 -68q-3 -3 -16.5 -18t-19 -20.5 t-18.5 -16.5t-22 -15.5t-22 -9t-26 -4.5q-40 0 -68 28l-408 408q-28 28 -28 68q0 13 4.5 26t9 22t15.5 22t16.5 18.5t20.5 19t18 16.5q30 28 68 28q10 0 18 -1.5t16.5 -5.5t13.5 -6t13.5 -10t11.5 -10t13 -12.5t12 -12.5q-14 14 -14 34t14 34l348 348q14 14 34 14t34 -14 q-2 2 -12.5 12t-12.5 13t-10 11.5t-10 13.5t-6 13.5t-5.5 16.5t-1.5 18q0 38 28 68q3 3 16.5 18t19 20.5t18.5 16.5t22 15.5t22 9t26 4.5q40 0 68 -28l408 -408q28 -28 28 -68q0 -13 -4.5 -26t-9 -22t-15.5 -22t-16.5 -18.5t-20.5 -19t-18 -16.5q-30 -28 -68 -28 q-10 0 -18 1.5t-16.5 5.5t-13.5 6t-13.5 10t-11.5 10t-13 12.5t-12 12.5q14 -14 14 -34t-14 -34l-126 -126l256 -256q43 43 96 43q52 0 91 -37l363 -363q37 -39 37 -91z" /> <glyph glyph-name="dashboard" unicode="" horiz-adv-x="1792" d="M384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM576 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1004 351l101 382q6 26 -7.5 48.5t-38.5 29.5 t-48 -6.5t-30 -39.5l-101 -382q-60 -5 -107 -43.5t-63 -98.5q-20 -77 20 -146t117 -89t146 20t89 117q16 60 -6 117t-72 91zM1664 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 1024q0 53 -37.5 90.5 t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1472 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 384q0 -261 -141 -483q-19 -29 -54 -29h-1402q-35 0 -54 29 q-141 221 -141 483q0 182 71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> <glyph glyph-name="comment_alt" unicode="" horiz-adv-x="1792" d="M896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640 q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 174 120 321.5 t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" /> <glyph glyph-name="comments_alt" unicode="" horiz-adv-x="1792" d="M704 1152q-153 0 -286 -52t-211.5 -141t-78.5 -191q0 -82 53 -158t149 -132l97 -56l-35 -84q34 20 62 39l44 31l53 -10q78 -14 153 -14q153 0 286 52t211.5 141t78.5 191t-78.5 191t-211.5 141t-286 52zM704 1280q191 0 353.5 -68.5t256.5 -186.5t94 -257t-94 -257 t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224q0 139 94 257t256.5 186.5 t353.5 68.5zM1526 111q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129 q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230q0 -120 -71 -224.5t-195 -176.5z" /> <glyph glyph-name="bolt" unicode="" horiz-adv-x="896" d="M885 970q18 -20 7 -44l-540 -1157q-13 -25 -42 -25q-4 0 -14 2q-17 5 -25.5 19t-4.5 30l197 808l-406 -101q-4 -1 -12 -1q-18 0 -31 11q-18 15 -13 39l201 825q4 14 16 23t28 9h328q19 0 32 -12.5t13 -29.5q0 -8 -5 -18l-171 -463l396 98q8 2 12 2q19 0 34 -15z" /> <glyph glyph-name="sitemap" unicode="" horiz-adv-x="1792" d="M1792 288v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192q0 52 38 90t90 38h512v192h-96q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h320q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-96v-192h512q52 0 90 -38t38 -90v-192h96q40 0 68 -28t28 -68 z" /> <glyph glyph-name="umbrella" unicode="" horiz-adv-x="1664" d="M896 708v-580q0 -104 -76 -180t-180 -76t-180 76t-76 180q0 26 19 45t45 19t45 -19t19 -45q0 -50 39 -89t89 -39t89 39t39 89v580q33 11 64 11t64 -11zM1664 681q0 -13 -9.5 -22.5t-22.5 -9.5q-11 0 -23 10q-49 46 -93 69t-102 23q-68 0 -128 -37t-103 -97 q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -28 -17q-18 0 -29 17q-4 6 -14.5 24t-17.5 28q-43 60 -102.5 97t-127.5 37t-127.5 -37t-102.5 -97q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -29 -17q-17 0 -28 17q-4 6 -14.5 24t-17.5 28q-43 60 -103 97t-128 37q-58 0 -102 -23t-93 -69 q-12 -10 -23 -10q-13 0 -22.5 9.5t-9.5 22.5q0 5 1 7q45 183 172.5 319.5t298 204.5t360.5 68q140 0 274.5 -40t246.5 -113.5t194.5 -187t115.5 -251.5q1 -2 1 -7zM896 1408v-98q-42 2 -64 2t-64 -2v98q0 26 19 45t45 19t45 -19t19 -45z" /> <glyph glyph-name="paste" unicode="" horiz-adv-x="1792" d="M768 -128h896v640h-416q-40 0 -68 28t-28 68v416h-384v-1152zM1024 1312v64q0 13 -9.5 22.5t-22.5 9.5h-704q-13 0 -22.5 -9.5t-9.5 -22.5v-64q0 -13 9.5 -22.5t22.5 -9.5h704q13 0 22.5 9.5t9.5 22.5zM1280 640h299l-299 299v-299zM1792 512v-672q0 -40 -28 -68t-68 -28 h-960q-40 0 -68 28t-28 68v160h-544q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1088q40 0 68 -28t28 -68v-328q21 -13 36 -28l408 -408q28 -28 48 -76t20 -88z" /> <glyph glyph-name="light_bulb" unicode="" horiz-adv-x="1024" d="M736 960q0 -13 -9.5 -22.5t-22.5 -9.5t-22.5 9.5t-9.5 22.5q0 46 -54 71t-106 25q-13 0 -22.5 9.5t-9.5 22.5t9.5 22.5t22.5 9.5q50 0 99.5 -16t87 -54t37.5 -90zM896 960q0 72 -34.5 134t-90 101.5t-123 62t-136.5 22.5t-136.5 -22.5t-123 -62t-90 -101.5t-34.5 -134 q0 -101 68 -180q10 -11 30.5 -33t30.5 -33q128 -153 141 -298h228q13 145 141 298q10 11 30.5 33t30.5 33q68 79 68 180zM1024 960q0 -155 -103 -268q-45 -49 -74.5 -87t-59.5 -95.5t-34 -107.5q47 -28 47 -82q0 -37 -25 -64q25 -27 25 -64q0 -52 -45 -81q13 -23 13 -47 q0 -46 -31.5 -71t-77.5 -25q-20 -44 -60 -70t-87 -26t-87 26t-60 70q-46 0 -77.5 25t-31.5 71q0 24 13 47q-45 29 -45 81q0 37 25 64q-25 27 -25 64q0 54 47 82q-4 50 -34 107.5t-59.5 95.5t-74.5 87q-103 113 -103 268q0 99 44.5 184.5t117 142t164 89t186.5 32.5 t186.5 -32.5t164 -89t117 -142t44.5 -184.5z" /> <glyph glyph-name="exchange" unicode="" horiz-adv-x="1792" d="M1792 352v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5q-12 0 -24 10l-319 320q-9 9 -9 22q0 14 9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h1376q13 0 22.5 -9.5t9.5 -22.5zM1792 896q0 -14 -9 -23l-320 -320q-9 -9 -23 -9 q-13 0 -22.5 9.5t-9.5 22.5v192h-1376q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1376v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" /> <glyph glyph-name="cloud_download" unicode="" horiz-adv-x="1920" d="M1280 608q0 14 -9 23t-23 9h-224v352q0 13 -9.5 22.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-352h-224q-13 0 -22.5 -9.5t-9.5 -22.5q0 -14 9 -23l352 -352q9 -9 23 -9t23 9l351 351q10 12 10 24zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" /> <glyph glyph-name="cloud_upload" unicode="" horiz-adv-x="1920" d="M1280 672q0 14 -9 23l-352 352q-9 9 -23 9t-23 -9l-351 -351q-10 -12 -10 -24q0 -14 9 -23t23 -9h224v-352q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5v352h224q13 0 22.5 9.5t9.5 22.5zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" /> <glyph glyph-name="user_md" unicode="" horiz-adv-x="1408" d="M384 192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 68 5.5 131t24 138t47.5 132.5t81 103t120 60.5q-22 -52 -22 -120v-203q-58 -20 -93 -70t-35 -111q0 -80 56 -136t136 -56 t136 56t56 136q0 61 -35.5 111t-92.5 70v203q0 62 25 93q132 -104 295 -104t295 104q25 -31 25 -93v-64q-106 0 -181 -75t-75 -181v-89q-32 -29 -32 -71q0 -40 28 -68t68 -28t68 28t28 68q0 42 -32 71v89q0 52 38 90t90 38t90 -38t38 -90v-89q-32 -29 -32 -71q0 -40 28 -68 t68 -28t68 28t28 68q0 42 -32 71v89q0 68 -34.5 127.5t-93.5 93.5q0 10 0.5 42.5t0 48t-2.5 41.5t-7 47t-13 40q68 -15 120 -60.5t81 -103t47.5 -132.5t24 -138t5.5 -131zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" /> <glyph glyph-name="stethoscope" unicode="" horiz-adv-x="1408" d="M1280 832q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 832q0 -62 -35.5 -111t-92.5 -70v-395q0 -159 -131.5 -271.5t-316.5 -112.5t-316.5 112.5t-131.5 271.5v132q-164 20 -274 128t-110 252v512q0 26 19 45t45 19q6 0 16 -2q17 30 47 48 t65 18q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5q-33 0 -64 18v-402q0 -106 94 -181t226 -75t226 75t94 181v402q-31 -18 -64 -18q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5q35 0 65 -18t47 -48q10 2 16 2q26 0 45 -19t19 -45v-512q0 -144 -110 -252 t-274 -128v-132q0 -106 94 -181t226 -75t226 75t94 181v395q-57 21 -92.5 70t-35.5 111q0 80 56 136t136 56t136 -56t56 -136z" /> <glyph glyph-name="suitcase" unicode="" horiz-adv-x="1792" d="M640 1152h512v128h-512v-128zM288 1152v-1280h-64q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h64zM1408 1152v-1280h-1024v1280h128v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h128zM1792 928v-832q0 -92 -66 -158t-158 -66h-64v1280h64q92 0 158 -66 t66 -158z" /> <glyph glyph-name="bell_alt" unicode="" horiz-adv-x="1792" d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5 t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" /> <glyph glyph-name="coffee" unicode="" horiz-adv-x="1920" d="M1664 896q0 80 -56 136t-136 56h-64v-384h64q80 0 136 56t56 136zM0 128h1792q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM1856 896q0 -159 -112.5 -271.5t-271.5 -112.5h-64v-32q0 -92 -66 -158t-158 -66h-704q-92 0 -158 66t-66 158v736q0 26 19 45 t45 19h1152q159 0 271.5 -112.5t112.5 -271.5z" /> <glyph glyph-name="food" unicode="" horiz-adv-x="1408" d="M640 1472v-640q0 -61 -35.5 -111t-92.5 -70v-779q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v779q-57 20 -92.5 70t-35.5 111v640q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45 t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45zM1408 1472v-1600q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v512h-224q-13 0 -22.5 9.5t-9.5 22.5v800q0 132 94 226t226 94h256q26 0 45 -19t19 -45z" /> <glyph glyph-name="file_text_alt" unicode="" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M384 736q0 14 9 23t23 9h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64zM1120 512q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704zM1120 256q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704 q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704z" /> <glyph glyph-name="building" unicode="" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1536h-1152v-1536h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM1408 1472v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280q26 0 45 -19t19 -45z" /> <glyph glyph-name="hospital" unicode="" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1152h-256v-32q0 -40 -28 -68t-68 -28h-448q-40 0 -68 28t-28 68v32h-256v-1152h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM896 1056v320q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-96h-128v96q0 13 -9.5 22.5 t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5v96h128v-96q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1408 1088v-1280q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1280q0 26 19 45t45 19h320 v288q0 40 28 68t68 28h448q40 0 68 -28t28 -68v-288h320q26 0 45 -19t19 -45z" /> <glyph glyph-name="ambulance" unicode="" horiz-adv-x="1920" d="M640 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM256 640h384v256h-158q-14 -2 -22 -9l-195 -195q-7 -12 -9 -22v-30zM1536 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1664 800v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM1920 1344v-1152 q0 -26 -19 -45t-45 -19h-192q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-128q-26 0 -45 19t-19 45t19 45t45 19v416q0 26 13 58t32 51l198 198q19 19 51 32t58 13h160v320q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" /> <glyph glyph-name="medkit" unicode="" horiz-adv-x="1792" d="M1280 416v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM640 1152h512v128h-512v-128zM256 1152v-1280h-32 q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h32zM1440 1152v-1280h-1088v1280h160v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h160zM1792 928v-832q0 -92 -66 -158t-158 -66h-32v1280h32q92 0 158 -66t66 -158z" /> <glyph glyph-name="fighter_jet" unicode="" horiz-adv-x="1920" d="M1920 576q-1 -32 -288 -96l-352 -32l-224 -64h-64l-293 -352h69q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-96h-160h-64v32h64v416h-160l-192 -224h-96l-32 32v192h32v32h128v8l-192 24v128l192 24v8h-128v32h-32v192l32 32h96l192 -224h160v416h-64v32h64h160h96 q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-69l293 -352h64l224 -64l352 -32q128 -28 200 -52t80 -34z" /> <glyph glyph-name="beer" unicode="" horiz-adv-x="1664" d="M640 640v384h-256v-256q0 -53 37.5 -90.5t90.5 -37.5h128zM1664 192v-192h-1152v192l128 192h-128q-159 0 -271.5 112.5t-112.5 271.5v320l-64 64l32 128h480l32 128h960l32 -192l-64 -32v-800z" /> <glyph glyph-name="h_sign" unicode="" d="M1280 192v896q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-512v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h512v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="f0fe" unicode="" d="M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="double_angle_left" unicode="" horiz-adv-x="1024" d="M627 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23zM1011 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23z" /> <glyph glyph-name="double_angle_right" unicode="" horiz-adv-x="1024" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM979 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23 l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" /> <glyph glyph-name="double_angle_up" unicode="" horiz-adv-x="1152" d="M1075 224q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM1075 608q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393 q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" /> <glyph glyph-name="double_angle_down" unicode="" horiz-adv-x="1152" d="M1075 672q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23zM1075 1056q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" /> <glyph glyph-name="angle_left" unicode="" horiz-adv-x="640" d="M627 992q0 -13 -10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" /> <glyph glyph-name="angle_right" unicode="" horiz-adv-x="640" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" /> <glyph glyph-name="angle_up" unicode="" horiz-adv-x="1152" d="M1075 352q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" /> <glyph glyph-name="angle_down" unicode="" horiz-adv-x="1152" d="M1075 800q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" /> <glyph glyph-name="desktop" unicode="" horiz-adv-x="1920" d="M1792 544v832q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1376v-1088q0 -66 -47 -113t-113 -47h-544q0 -37 16 -77.5t32 -71t16 -43.5q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19 t-19 45q0 14 16 44t32 70t16 78h-544q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" /> <glyph glyph-name="laptop" unicode="" horiz-adv-x="1920" d="M416 256q-66 0 -113 47t-47 113v704q0 66 47 113t113 47h1088q66 0 113 -47t47 -113v-704q0 -66 -47 -113t-113 -47h-1088zM384 1120v-704q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5v704q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5z M1760 192h160v-96q0 -40 -47 -68t-113 -28h-1600q-66 0 -113 28t-47 68v96h160h1600zM1040 96q16 0 16 16t-16 16h-160q-16 0 -16 -16t16 -16h160z" /> <glyph glyph-name="tablet" unicode="" horiz-adv-x="1152" d="M640 128q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1024 288v960q0 13 -9.5 22.5t-22.5 9.5h-832q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h832q13 0 22.5 9.5t9.5 22.5zM1152 1248v-1088q0 -66 -47 -113t-113 -47h-832 q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h832q66 0 113 -47t47 -113z" /> <glyph glyph-name="mobile_phone" unicode="" horiz-adv-x="768" d="M464 128q0 33 -23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5t56.5 23.5t23.5 56.5zM672 288v704q0 13 -9.5 22.5t-22.5 9.5h-512q-13 0 -22.5 -9.5t-9.5 -22.5v-704q0 -13 9.5 -22.5t22.5 -9.5h512q13 0 22.5 9.5t9.5 22.5zM480 1136 q0 16 -16 16h-160q-16 0 -16 -16t16 -16h160q16 0 16 16zM768 1152v-1024q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v1024q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" /> <glyph glyph-name="circle_blank" unicode="" d="M768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103 t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="quote_left" unicode="" horiz-adv-x="1664" d="M768 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z M1664 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z" /> <glyph glyph-name="quote_right" unicode="" horiz-adv-x="1664" d="M768 1216v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136zM1664 1216 v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136z" /> <glyph glyph-name="spinner" unicode="" horiz-adv-x="1792" d="M526 142q0 -53 -37.5 -90.5t-90.5 -37.5q-52 0 -90 38t-38 90q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1024 -64q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM320 640q0 -53 -37.5 -90.5t-90.5 -37.5 t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1522 142q0 -52 -38 -90t-90 -38q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM558 1138q0 -66 -47 -113t-113 -47t-113 47t-47 113t47 113t113 47t113 -47t47 -113z M1728 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1088 1344q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1618 1138q0 -93 -66 -158.5t-158 -65.5q-93 0 -158.5 65.5t-65.5 158.5 q0 92 65.5 158t158.5 66q92 0 158 -66t66 -158z" /> <glyph glyph-name="circle" unicode="" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="reply" unicode="" horiz-adv-x="1792" d="M1792 416q0 -166 -127 -451q-3 -7 -10.5 -24t-13.5 -30t-13 -22q-12 -17 -28 -17q-15 0 -23.5 10t-8.5 25q0 9 2.5 26.5t2.5 23.5q5 68 5 123q0 101 -17.5 181t-48.5 138.5t-80 101t-105.5 69.5t-133 42.5t-154 21.5t-175.5 6h-224v-256q0 -26 -19 -45t-45 -19t-45 19 l-512 512q-19 19 -19 45t19 45l512 512q19 19 45 19t45 -19t19 -45v-256h224q713 0 875 -403q53 -134 53 -333z" /> <glyph glyph-name="github_alt" unicode="" horiz-adv-x="1664" d="M640 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1280 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1440 320 q0 120 -69 204t-187 84q-41 0 -195 -21q-71 -11 -157 -11t-157 11q-152 21 -195 21q-118 0 -187 -84t-69 -204q0 -88 32 -153.5t81 -103t122 -60t140 -29.5t149 -7h168q82 0 149 7t140 29.5t122 60t81 103t32 153.5zM1664 496q0 -207 -61 -331q-38 -77 -105.5 -133t-141 -86 t-170 -47.5t-171.5 -22t-167 -4.5q-78 0 -142 3t-147.5 12.5t-152.5 30t-137 51.5t-121 81t-86 115q-62 123 -62 331q0 237 136 396q-27 82 -27 170q0 116 51 218q108 0 190 -39.5t189 -123.5q147 35 309 35q148 0 280 -32q105 82 187 121t189 39q51 -102 51 -218 q0 -87 -27 -168q136 -160 136 -398z" /> <glyph glyph-name="folder_close_alt" unicode="" horiz-adv-x="1664" d="M1536 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68v-960q0 -40 28 -68t68 -28h1216q40 0 68 28t28 68zM1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320 q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" /> <glyph glyph-name="folder_open_alt" unicode="" horiz-adv-x="1920" d="M1781 605q0 35 -53 35h-1088q-40 0 -85.5 -21.5t-71.5 -52.5l-294 -363q-18 -24 -18 -40q0 -35 53 -35h1088q40 0 86 22t71 53l294 363q18 22 18 39zM640 768h768v160q0 40 -28 68t-68 28h-576q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68 v-853l256 315q44 53 116 87.5t140 34.5zM1909 605q0 -62 -46 -120l-295 -363q-43 -53 -116 -87.5t-140 -34.5h-1088q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158v-160h192q54 0 99 -24.5t67 -70.5q15 -32 15 -68z " /> <glyph glyph-name="expand_alt" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="collapse_alt" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="smile" unicode="" d="M1134 461q-37 -121 -138 -195t-228 -74t-228 74t-138 195q-8 25 4 48.5t38 31.5q25 8 48.5 -4t31.5 -38q25 -80 92.5 -129.5t151.5 -49.5t151.5 49.5t92.5 129.5q8 26 32 38t49 4t37 -31.5t4 -48.5zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5 t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="frown" unicode="" d="M1134 307q8 -25 -4 -48.5t-37 -31.5t-49 4t-32 38q-25 80 -92.5 129.5t-151.5 49.5t-151.5 -49.5t-92.5 -129.5q-8 -26 -31.5 -38t-48.5 -4q-26 8 -38 31.5t-4 48.5q37 121 138 195t228 74t228 -74t138 -195zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204 t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="meh" unicode="" d="M1152 448q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h640q26 0 45 -19t19 -45zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="gamepad" unicode="" horiz-adv-x="1920" d="M832 448v128q0 14 -9 23t-23 9h-192v192q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-192h-192q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h192v-192q0 -14 9 -23t23 -9h128q14 0 23 9t9 23v192h192q14 0 23 9t9 23zM1408 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1920 512q0 -212 -150 -362t-362 -150q-192 0 -338 128h-220q-146 -128 -338 -128q-212 0 -362 150 t-150 362t150 362t362 150h896q212 0 362 -150t150 -362z" /> <glyph glyph-name="keyboard" unicode="" horiz-adv-x="1920" d="M384 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM512 624v-96q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h224q16 0 16 -16zM384 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 368v-96q0 -16 -16 -16 h-864q-16 0 -16 16v96q0 16 16 16h864q16 0 16 -16zM768 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM640 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1024 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16 h96q16 0 16 -16zM896 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1280 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1152 880v-96 q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 880v-352q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h112v240q0 16 16 16h96q16 0 16 -16zM1792 128v896h-1664v-896 h1664zM1920 1024v-896q0 -53 -37.5 -90.5t-90.5 -37.5h-1664q-53 0 -90.5 37.5t-37.5 90.5v896q0 53 37.5 90.5t90.5 37.5h1664q53 0 90.5 -37.5t37.5 -90.5z" /> <glyph glyph-name="flag_alt" unicode="" horiz-adv-x="1792" d="M1664 491v616q-169 -91 -306 -91q-82 0 -145 32q-100 49 -184 76.5t-178 27.5q-173 0 -403 -127v-599q245 113 433 113q55 0 103.5 -7.5t98 -26t77 -31t82.5 -39.5l28 -14q44 -22 101 -22q120 0 293 92zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9 h-64q-14 0 -23 9t-9 23v1266q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102 q-15 -9 -33 -9q-16 0 -32 8q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" /> <glyph glyph-name="flag_checkered" unicode="" horiz-adv-x="1792" d="M832 536v192q-181 -16 -384 -117v-185q205 96 384 110zM832 954v197q-172 -8 -384 -126v-189q215 111 384 118zM1664 491v184q-235 -116 -384 -71v224q-20 6 -39 15q-5 3 -33 17t-34.5 17t-31.5 15t-34.5 15.5t-32.5 13t-36 12.5t-35 8.5t-39.5 7.5t-39.5 4t-44 2 q-23 0 -49 -3v-222h19q102 0 192.5 -29t197.5 -82q19 -9 39 -15v-188q42 -17 91 -17q120 0 293 92zM1664 918v189q-169 -91 -306 -91q-45 0 -78 8v-196q148 -42 384 90zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v1266 q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102q-15 -9 -33 -9q-16 0 -32 8 q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" /> <glyph glyph-name="terminal" unicode="" horiz-adv-x="1664" d="M585 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23zM1664 96v-64q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h960q14 0 23 -9 t9 -23z" /> <glyph glyph-name="code" unicode="" horiz-adv-x="1920" d="M617 137l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23zM1208 1204l-373 -1291q-4 -13 -15.5 -19.5t-23.5 -2.5l-62 17q-13 4 -19.5 15.5t-2.5 24.5 l373 1291q4 13 15.5 19.5t23.5 2.5l62 -17q13 -4 19.5 -15.5t2.5 -24.5zM1865 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23z" /> <glyph glyph-name="reply_all" unicode="" horiz-adv-x="1792" d="M640 454v-70q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-69l-397 -398q-19 -19 -19 -45t19 -45zM1792 416q0 -58 -17 -133.5t-38.5 -138t-48 -125t-40.5 -90.5l-20 -40q-8 -17 -28 -17q-6 0 -9 1 q-25 8 -23 34q43 400 -106 565q-64 71 -170.5 110.5t-267.5 52.5v-251q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-262q411 -28 599 -221q169 -173 169 -509z" /> <glyph glyph-name="star_half_empty" unicode="" horiz-adv-x="1664" d="M1186 579l257 250l-356 52l-66 10l-30 60l-159 322v-963l59 -31l318 -168l-60 355l-12 66zM1638 841l-363 -354l86 -500q5 -33 -6 -51.5t-34 -18.5q-17 0 -40 12l-449 236l-449 -236q-23 -12 -40 -12q-23 0 -34 18.5t-6 51.5l86 500l-364 354q-32 32 -23 59.5t54 34.5 l502 73l225 455q20 41 49 41q28 0 49 -41l225 -455l502 -73q45 -7 54 -34.5t-24 -59.5z" /> <glyph glyph-name="location_arrow" unicode="" horiz-adv-x="1408" d="M1401 1187l-640 -1280q-17 -35 -57 -35q-5 0 -15 2q-22 5 -35.5 22.5t-13.5 39.5v576h-576q-22 0 -39.5 13.5t-22.5 35.5t4 42t29 30l1280 640q13 7 29 7q27 0 45 -19q15 -14 18.5 -34.5t-6.5 -39.5z" /> <glyph glyph-name="crop" unicode="" horiz-adv-x="1664" d="M557 256h595v595zM512 301l595 595h-595v-595zM1664 224v-192q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v224h-864q-14 0 -23 9t-9 23v864h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224v224q0 14 9 23t23 9h192q14 0 23 -9t9 -23 v-224h851l246 247q10 9 23 9t23 -9q9 -10 9 -23t-9 -23l-247 -246v-851h224q14 0 23 -9t9 -23z" /> <glyph glyph-name="code_fork" unicode="" horiz-adv-x="1024" d="M288 64q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM288 1216q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM928 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1024 1088q0 -52 -26 -96.5t-70 -69.5 q-2 -287 -226 -414q-67 -38 -203 -81q-128 -40 -169.5 -71t-41.5 -100v-26q44 -25 70 -69.5t26 -96.5q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 52 26 96.5t70 69.5v820q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136q0 -52 -26 -96.5t-70 -69.5v-497 q54 26 154 57q55 17 87.5 29.5t70.5 31t59 39.5t40.5 51t28 69.5t8.5 91.5q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136z" /> <glyph glyph-name="unlink" unicode="" horiz-adv-x="1664" d="M439 265l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23zM608 224v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM384 448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23t9 23t23 9h320 q14 0 23 -9t9 -23zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-334 335q-21 21 -42 56l239 18l273 -274q27 -27 68 -27.5t68 26.5l147 146q28 28 28 67q0 40 -28 68l-274 275l18 239q35 -21 56 -42l336 -336q84 -86 84 -204zM1031 1044l-239 -18 l-273 274q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l274 -274l-18 -240q-35 21 -56 42l-336 336q-84 86 -84 204q0 120 85 203l147 146q83 83 203 83q121 0 204 -85l334 -335q21 -21 42 -56zM1664 960q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9 t-9 23t9 23t23 9h320q14 0 23 -9t9 -23zM1120 1504v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM1527 1353l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" /> <glyph glyph-name="question" unicode="" horiz-adv-x="1024" d="M704 280v-240q0 -16 -12 -28t-28 -12h-240q-16 0 -28 12t-12 28v240q0 16 12 28t28 12h240q16 0 28 -12t12 -28zM1020 880q0 -54 -15.5 -101t-35 -76.5t-55 -59.5t-57.5 -43.5t-61 -35.5q-41 -23 -68.5 -65t-27.5 -67q0 -17 -12 -32.5t-28 -15.5h-240q-15 0 -25.5 18.5 t-10.5 37.5v45q0 83 65 156.5t143 108.5q59 27 84 56t25 76q0 42 -46.5 74t-107.5 32q-65 0 -108 -29q-35 -25 -107 -115q-13 -16 -31 -16q-12 0 -25 8l-164 125q-13 10 -15.5 25t5.5 28q160 266 464 266q80 0 161 -31t146 -83t106 -127.5t41 -158.5z" /> <glyph glyph-name="_279" unicode="" horiz-adv-x="640" d="M640 192v-128q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64v384h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-576h64q26 0 45 -19t19 -45zM512 1344v-192q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v192 q0 26 19 45t45 19h256q26 0 45 -19t19 -45z" /> <glyph glyph-name="exclamation" unicode="" horiz-adv-x="640" d="M512 288v-224q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v224q0 26 19 45t45 19h256q26 0 45 -19t19 -45zM542 1344l-28 -768q-1 -26 -20.5 -45t-45.5 -19h-256q-26 0 -45.5 19t-20.5 45l-28 768q-1 26 17.5 45t44.5 19h320q26 0 44.5 -19t17.5 -45z" /> <glyph glyph-name="superscript" unicode="" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3q-1 -3 -2.5 -6.5t-3.5 -8t-3 -6.5q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109z M1534 846v-206h-514l-3 27q-4 28 -4 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q83 65 188 65q110 0 178 -59.5t68 -158.5q0 -56 -24.5 -103t-62 -76.5t-81.5 -58.5t-82 -50.5 t-65.5 -51.5t-30.5 -63h232v80h126z" /> <glyph glyph-name="subscript" unicode="" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3q-1 -3 -2.5 -6.5t-3.5 -8t-3 -6.5q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109z M1536 -50v-206h-514l-4 27q-3 45 -3 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q80 65 188 65q110 0 178 -59.5t68 -158.5q0 -66 -34.5 -118.5t-84 -86t-99.5 -62.5t-87 -63t-41 -73 h232v80h126z" /> <glyph glyph-name="_283" unicode="" horiz-adv-x="1920" d="M896 128l336 384h-768l-336 -384h768zM1909 1205q15 -34 9.5 -71.5t-30.5 -65.5l-896 -1024q-38 -44 -96 -44h-768q-38 0 -69.5 20.5t-47.5 54.5q-15 34 -9.5 71.5t30.5 65.5l896 1024q38 44 96 44h768q38 0 69.5 -20.5t47.5 -54.5z" /> <glyph glyph-name="puzzle_piece" unicode="" horiz-adv-x="1664" d="M1664 438q0 -81 -44.5 -135t-123.5 -54q-41 0 -77.5 17.5t-59 38t-56.5 38t-71 17.5q-110 0 -110 -124q0 -39 16 -115t15 -115v-5q-22 0 -33 -1q-34 -3 -97.5 -11.5t-115.5 -13.5t-98 -5q-61 0 -103 26.5t-42 83.5q0 37 17.5 71t38 56.5t38 59t17.5 77.5q0 79 -54 123.5 t-135 44.5q-84 0 -143 -45.5t-59 -127.5q0 -43 15 -83t33.5 -64.5t33.5 -53t15 -50.5q0 -45 -46 -89q-37 -35 -117 -35q-95 0 -245 24q-9 2 -27.5 4t-27.5 4l-13 2q-1 0 -3 1q-2 0 -2 1v1024q2 -1 17.5 -3.5t34 -5t21.5 -3.5q150 -24 245 -24q80 0 117 35q46 44 46 89 q0 22 -15 50.5t-33.5 53t-33.5 64.5t-15 83q0 82 59 127.5t144 45.5q80 0 134 -44.5t54 -123.5q0 -41 -17.5 -77.5t-38 -59t-38 -56.5t-17.5 -71q0 -57 42 -83.5t103 -26.5q64 0 180 15t163 17v-2q-1 -2 -3.5 -17.5t-5 -34t-3.5 -21.5q-24 -150 -24 -245q0 -80 35 -117 q44 -46 89 -46q22 0 50.5 15t53 33.5t64.5 33.5t83 15q82 0 127.5 -59t45.5 -143z" /> <glyph glyph-name="microphone" unicode="" horiz-adv-x="1152" d="M1152 832v-128q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-217 24 -364.5 187.5t-147.5 384.5v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -185 131.5 -316.5t316.5 -131.5 t316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45zM896 1216v-512q0 -132 -94 -226t-226 -94t-226 94t-94 226v512q0 132 94 226t226 94t226 -94t94 -226z" /> <glyph glyph-name="microphone_off" unicode="" horiz-adv-x="1408" d="M271 591l-101 -101q-42 103 -42 214v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -53 15 -113zM1385 1193l-361 -361v-128q0 -132 -94 -226t-226 -94q-55 0 -109 19l-96 -96q97 -51 205 -51q185 0 316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45v-128 q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-125 13 -235 81l-254 -254q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l1234 1234q10 10 23 10t23 -10l82 -82q10 -10 10 -23 t-10 -23zM1005 1325l-621 -621v512q0 132 94 226t226 94q102 0 184.5 -59t116.5 -152z" /> <glyph glyph-name="shield" unicode="" horiz-adv-x="1280" d="M1088 576v640h-448v-1137q119 63 213 137q235 184 235 360zM1280 1344v-768q0 -86 -33.5 -170.5t-83 -150t-118 -127.5t-126.5 -103t-121 -77.5t-89.5 -49.5t-42.5 -20q-12 -6 -26 -6t-26 6q-16 7 -42.5 20t-89.5 49.5t-121 77.5t-126.5 103t-118 127.5t-83 150 t-33.5 170.5v768q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" /> <glyph glyph-name="calendar_empty" unicode="" horiz-adv-x="1664" d="M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" /> <glyph glyph-name="fire_extinguisher" unicode="" horiz-adv-x="1408" d="M512 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 1376v-320q0 -16 -12 -25q-8 -7 -20 -7q-4 0 -7 1l-448 96q-11 2 -18 11t-7 20h-256v-102q111 -23 183.5 -111t72.5 -203v-800q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v800 q0 106 62.5 190.5t161.5 114.5v111h-32q-59 0 -115 -23.5t-91.5 -53t-66 -66.5t-40.5 -53.5t-14 -24.5q-17 -35 -57 -35q-16 0 -29 7q-23 12 -31.5 37t3.5 49q5 10 14.5 26t37.5 53.5t60.5 70t85 67t108.5 52.5q-25 42 -25 86q0 66 47 113t113 47t113 -47t47 -113 q0 -33 -14 -64h302q0 11 7 20t18 11l448 96q3 1 7 1q12 0 20 -7q12 -9 12 -25z" /> <glyph glyph-name="rocket" unicode="" horiz-adv-x="1664" d="M1440 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1664 1376q0 -249 -75.5 -430.5t-253.5 -360.5q-81 -80 -195 -176l-20 -379q-2 -16 -16 -26l-384 -224q-7 -4 -16 -4q-12 0 -23 9l-64 64q-13 14 -8 32l85 276l-281 281l-276 -85q-3 -1 -9 -1 q-14 0 -23 9l-64 64q-17 19 -5 39l224 384q10 14 26 16l379 20q96 114 176 195q188 187 358 258t431 71q14 0 24 -9.5t10 -22.5z" /> <glyph glyph-name="maxcdn" unicode="" horiz-adv-x="1792" d="M1745 763l-164 -763h-334l178 832q13 56 -15 88q-27 33 -83 33h-169l-204 -953h-334l204 953h-286l-204 -953h-334l204 953l-153 327h1276q101 0 189.5 -40.5t147.5 -113.5q60 -73 81 -168.5t0 -194.5z" /> <glyph glyph-name="chevron_sign_left" unicode="" d="M909 141l102 102q19 19 19 45t-19 45l-307 307l307 307q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="chevron_sign_right" unicode="" d="M717 141l454 454q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l307 -307l-307 -307q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="chevron_sign_up" unicode="" d="M1165 397l102 102q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l307 307l307 -307q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="chevron_sign_down" unicode="" d="M813 237l454 454q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-307 -307l-307 307q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="html5" unicode="" horiz-adv-x="1408" d="M1130 939l16 175h-884l47 -534h612l-22 -228l-197 -53l-196 53l-13 140h-175l22 -278l362 -100h4v1l359 99l50 544h-644l-15 181h674zM0 1408h1408l-128 -1438l-578 -162l-574 162z" /> <glyph glyph-name="css3" unicode="" horiz-adv-x="1792" d="M275 1408h1505l-266 -1333l-804 -267l-698 267l71 356h297l-29 -147l422 -161l486 161l68 339h-1208l58 297h1209l38 191h-1208z" /> <glyph glyph-name="anchor" unicode="" horiz-adv-x="1792" d="M960 1280q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1792 352v-352q0 -22 -20 -30q-8 -2 -12 -2q-12 0 -23 9l-93 93q-119 -143 -318.5 -226.5t-429.5 -83.5t-429.5 83.5t-318.5 226.5l-93 -93q-9 -9 -23 -9q-4 0 -12 2q-20 8 -20 30v352 q0 14 9 23t23 9h352q22 0 30 -20q8 -19 -7 -35l-100 -100q67 -91 189.5 -153.5t271.5 -82.5v647h-192q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h192v163q-58 34 -93 92.5t-35 128.5q0 106 75 181t181 75t181 -75t75 -181q0 -70 -35 -128.5t-93 -92.5v-163h192q26 0 45 -19 t19 -45v-128q0 -26 -19 -45t-45 -19h-192v-647q149 20 271.5 82.5t189.5 153.5l-100 100q-15 16 -7 35q8 20 30 20h352q14 0 23 -9t9 -23z" /> <glyph glyph-name="unlock_alt" unicode="" horiz-adv-x="1152" d="M1056 768q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v320q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45q0 106 -75 181t-181 75t-181 -75t-75 -181 v-320h736z" /> <glyph glyph-name="bullseye" unicode="" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM1152 640q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1280 640q0 -212 -150 -362t-362 -150t-362 150 t-150 362t150 362t362 150t362 -150t150 -362zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="ellipsis_horizontal" unicode="" horiz-adv-x="1408" d="M384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM896 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM1408 800v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" /> <glyph glyph-name="ellipsis_vertical" unicode="" horiz-adv-x="384" d="M384 288v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 1312v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" /> <glyph glyph-name="_303" unicode="" d="M512 256q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM863 162q-13 233 -176.5 396.5t-396.5 176.5q-14 1 -24 -9t-10 -23v-128q0 -13 8.5 -22t21.5 -10q154 -11 264 -121t121 -264q1 -13 10 -21.5t22 -8.5h128 q13 0 23 10t9 24zM1247 161q-5 154 -56 297.5t-139.5 260t-205 205t-260 139.5t-297.5 56q-14 1 -23 -9q-10 -10 -10 -23v-128q0 -13 9 -22t22 -10q204 -7 378 -111.5t278.5 -278.5t111.5 -378q1 -13 10 -22t22 -9h128q13 0 23 10q11 9 9 23zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="play_sign" unicode="" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1152 585q32 18 32 55t-32 55l-544 320q-31 19 -64 1q-32 -19 -32 -56v-640q0 -37 32 -56 q16 -8 32 -8q17 0 32 9z" /> <glyph glyph-name="ticket" unicode="" horiz-adv-x="1792" d="M1024 1084l316 -316l-572 -572l-316 316zM813 105l618 618q19 19 19 45t-19 45l-362 362q-18 18 -45 18t-45 -18l-618 -618q-19 -19 -19 -45t19 -45l362 -362q18 -18 45 -18t45 18zM1702 742l-907 -908q-37 -37 -90.5 -37t-90.5 37l-126 126q56 56 56 136t-56 136 t-136 56t-136 -56l-125 126q-37 37 -37 90.5t37 90.5l907 906q37 37 90.5 37t90.5 -37l125 -125q-56 -56 -56 -136t56 -136t136 -56t136 56l126 -125q37 -37 37 -90.5t-37 -90.5z" /> <glyph glyph-name="minus_sign_alt" unicode="" d="M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" /> <glyph glyph-name="check_minus" unicode="" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h832q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5 t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="level_up" unicode="" horiz-adv-x="1024" d="M1018 933q-18 -37 -58 -37h-192v-864q0 -14 -9 -23t-23 -9h-704q-21 0 -29 18q-8 20 4 35l160 192q9 11 25 11h320v640h-192q-40 0 -58 37q-17 37 9 68l320 384q18 22 49 22t49 -22l320 -384q27 -32 9 -68z" /> <glyph glyph-name="level_down" unicode="" horiz-adv-x="1024" d="M32 1280h704q13 0 22.5 -9.5t9.5 -23.5v-863h192q40 0 58 -37t-9 -69l-320 -384q-18 -22 -49 -22t-49 22l-320 384q-26 31 -9 69q18 37 58 37h192v640h-320q-14 0 -25 11l-160 192q-13 14 -4 34q9 19 29 19z" /> <glyph glyph-name="check_sign" unicode="" d="M685 237l614 614q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-467 -467l-211 211q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l358 -358q19 -19 45 -19t45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5 t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="edit_sign" unicode="" d="M404 428l152 -152l-52 -52h-56v96h-96v56zM818 818q14 -13 -3 -30l-291 -291q-17 -17 -30 -3q-14 13 3 30l291 291q17 17 30 3zM544 128l544 544l-288 288l-544 -544v-288h288zM1152 736l92 92q28 28 28 68t-28 68l-152 152q-28 28 -68 28t-68 -28l-92 -92zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="_312" unicode="" d="M1280 608v480q0 26 -19 45t-45 19h-480q-42 0 -59 -39q-17 -41 14 -70l144 -144l-534 -534q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l534 534l144 -144q18 -19 45 -19q12 0 25 5q39 17 39 59zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="share_sign" unicode="" d="M1005 435l352 352q19 19 19 45t-19 45l-352 352q-30 31 -69 14q-40 -17 -40 -59v-160q-119 0 -216 -19.5t-162.5 -51t-114 -79t-76.5 -95.5t-44.5 -109t-21.5 -111.5t-5 -110.5q0 -181 167 -404q11 -12 25 -12q7 0 13 3q22 9 19 33q-44 354 62 473q46 52 130 75.5 t224 23.5v-160q0 -42 40 -59q12 -5 24 -5q26 0 45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="compass" unicode="" d="M640 448l256 128l-256 128v-256zM1024 1039v-542l-512 -256v542zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="collapse" unicode="" d="M1145 861q18 -35 -5 -66l-320 -448q-19 -27 -52 -27t-52 27l-320 448q-23 31 -5 66q17 35 57 35h640q40 0 57 -35zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="collapse_top" unicode="" d="M1145 419q-17 -35 -57 -35h-640q-40 0 -57 35q-18 35 5 66l320 448q19 27 52 27t52 -27l320 -448q23 -31 5 -66zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="_317" unicode="" d="M1088 640q0 -33 -27 -52l-448 -320q-31 -23 -66 -5q-35 17 -35 57v640q0 40 35 57q35 18 66 -5l448 -320q27 -19 27 -52zM1280 160v960q0 14 -9 23t-23 9h-960q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h960q14 0 23 9t9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="eur" unicode="" horiz-adv-x="1024" d="M976 229l35 -159q3 -12 -3 -22.5t-17 -14.5l-5 -1q-4 -2 -10.5 -3.5t-16 -4.5t-21.5 -5.5t-25.5 -5t-30 -5t-33.5 -4.5t-36.5 -3t-38.5 -1q-234 0 -409 130.5t-238 351.5h-95q-13 0 -22.5 9.5t-9.5 22.5v113q0 13 9.5 22.5t22.5 9.5h66q-2 57 1 105h-67q-14 0 -23 9 t-9 23v114q0 14 9 23t23 9h98q67 210 243.5 338t400.5 128q102 0 194 -23q11 -3 20 -15q6 -11 3 -24l-43 -159q-3 -13 -14 -19.5t-24 -2.5l-4 1q-4 1 -11.5 2.5l-17.5 3.5t-22.5 3.5t-26 3t-29 2.5t-29.5 1q-126 0 -226 -64t-150 -176h468q16 0 25 -12q10 -12 7 -26 l-24 -114q-5 -26 -32 -26h-488q-3 -37 0 -105h459q15 0 25 -12q9 -12 6 -27l-24 -112q-2 -11 -11 -18.5t-20 -7.5h-387q48 -117 149.5 -185.5t228.5 -68.5q18 0 36 1.5t33.5 3.5t29.5 4.5t24.5 5t18.5 4.5l12 3l5 2q13 5 26 -2q12 -7 15 -21z" /> <glyph glyph-name="gbp" unicode="" horiz-adv-x="1024" d="M1020 399v-367q0 -14 -9 -23t-23 -9h-956q-14 0 -23 9t-9 23v150q0 13 9.5 22.5t22.5 9.5h97v383h-95q-14 0 -23 9.5t-9 22.5v131q0 14 9 23t23 9h95v223q0 171 123.5 282t314.5 111q185 0 335 -125q9 -8 10 -20.5t-7 -22.5l-103 -127q-9 -11 -22 -12q-13 -2 -23 7 q-5 5 -26 19t-69 32t-93 18q-85 0 -137 -47t-52 -123v-215h305q13 0 22.5 -9t9.5 -23v-131q0 -13 -9.5 -22.5t-22.5 -9.5h-305v-379h414v181q0 13 9 22.5t23 9.5h162q14 0 23 -9.5t9 -22.5z" /> <glyph glyph-name="usd" unicode="" horiz-adv-x="1024" d="M978 351q0 -153 -99.5 -263.5t-258.5 -136.5v-175q0 -14 -9 -23t-23 -9h-135q-13 0 -22.5 9.5t-9.5 22.5v175q-66 9 -127.5 31t-101.5 44.5t-74 48t-46.5 37.5t-17.5 18q-17 21 -2 41l103 135q7 10 23 12q15 2 24 -9l2 -2q113 -99 243 -125q37 -8 74 -8q81 0 142.5 43 t61.5 122q0 28 -15 53t-33.5 42t-58.5 37.5t-66 32t-80 32.5q-39 16 -61.5 25t-61.5 26.5t-62.5 31t-56.5 35.5t-53.5 42.5t-43.5 49t-35.5 58t-21 66.5t-8.5 78q0 138 98 242t255 134v180q0 13 9.5 22.5t22.5 9.5h135q14 0 23 -9t9 -23v-176q57 -6 110.5 -23t87 -33.5 t63.5 -37.5t39 -29t15 -14q17 -18 5 -38l-81 -146q-8 -15 -23 -16q-14 -3 -27 7q-3 3 -14.5 12t-39 26.5t-58.5 32t-74.5 26t-85.5 11.5q-95 0 -155 -43t-60 -111q0 -26 8.5 -48t29.5 -41.5t39.5 -33t56 -31t60.5 -27t70 -27.5q53 -20 81 -31.5t76 -35t75.5 -42.5t62 -50 t53 -63.5t31.5 -76.5t13 -94z" /> <glyph glyph-name="inr" unicode="" horiz-adv-x="898" d="M898 1066v-102q0 -14 -9 -23t-23 -9h-168q-23 -144 -129 -234t-276 -110q167 -178 459 -536q14 -16 4 -34q-8 -18 -29 -18h-195q-16 0 -25 12q-306 367 -498 571q-9 9 -9 22v127q0 13 9.5 22.5t22.5 9.5h112q132 0 212.5 43t102.5 125h-427q-14 0 -23 9t-9 23v102 q0 14 9 23t23 9h413q-57 113 -268 113h-145q-13 0 -22.5 9.5t-9.5 22.5v133q0 14 9 23t23 9h832q14 0 23 -9t9 -23v-102q0 -14 -9 -23t-23 -9h-233q47 -61 64 -144h171q14 0 23 -9t9 -23z" /> <glyph glyph-name="jpy" unicode="" horiz-adv-x="1027" d="M603 0h-172q-13 0 -22.5 9t-9.5 23v330h-288q-13 0 -22.5 9t-9.5 23v103q0 13 9.5 22.5t22.5 9.5h288v85h-288q-13 0 -22.5 9t-9.5 23v104q0 13 9.5 22.5t22.5 9.5h214l-321 578q-8 16 0 32q10 16 28 16h194q19 0 29 -18l215 -425q19 -38 56 -125q10 24 30.5 68t27.5 61 l191 420q8 19 29 19h191q17 0 27 -16q9 -14 1 -31l-313 -579h215q13 0 22.5 -9.5t9.5 -22.5v-104q0 -14 -9.5 -23t-22.5 -9h-290v-85h290q13 0 22.5 -9.5t9.5 -22.5v-103q0 -14 -9.5 -23t-22.5 -9h-290v-330q0 -13 -9.5 -22.5t-22.5 -9.5z" /> <glyph glyph-name="rub" unicode="" horiz-adv-x="1280" d="M1043 971q0 100 -65 162t-171 62h-320v-448h320q106 0 171 62t65 162zM1280 971q0 -193 -126.5 -315t-326.5 -122h-340v-118h505q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-505v-192q0 -14 -9.5 -23t-22.5 -9h-167q-14 0 -23 9t-9 23v192h-224q-14 0 -23 9t-9 23v128 q0 14 9 23t23 9h224v118h-224q-14 0 -23 9t-9 23v149q0 13 9 22.5t23 9.5h224v629q0 14 9 23t23 9h539q200 0 326.5 -122t126.5 -315z" /> <glyph glyph-name="krw" unicode="" horiz-adv-x="1792" d="M514 341l81 299h-159l75 -300q1 -1 1 -3t1 -3q0 1 0.5 3.5t0.5 3.5zM630 768l35 128h-292l32 -128h225zM822 768h139l-35 128h-70zM1271 340l78 300h-162l81 -299q0 -1 0.5 -3.5t1.5 -3.5q0 1 0.5 3t0.5 3zM1382 768l33 128h-297l34 -128h230zM1792 736v-64q0 -14 -9 -23 t-23 -9h-213l-164 -616q-7 -24 -31 -24h-159q-24 0 -31 24l-166 616h-209l-167 -616q-7 -24 -31 -24h-159q-11 0 -19.5 7t-10.5 17l-160 616h-208q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h175l-33 128h-142q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h109l-89 344q-5 15 5 28 q10 12 26 12h137q26 0 31 -24l90 -360h359l97 360q7 24 31 24h126q24 0 31 -24l98 -360h365l93 360q5 24 31 24h137q16 0 26 -12q10 -13 5 -28l-91 -344h111q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-145l-34 -128h179q14 0 23 -9t9 -23z" /> <glyph glyph-name="btc" unicode="" horiz-adv-x="1280" d="M1167 896q18 -182 -131 -258q117 -28 175 -103t45 -214q-7 -71 -32.5 -125t-64.5 -89t-97 -58.5t-121.5 -34.5t-145.5 -15v-255h-154v251q-80 0 -122 1v-252h-154v255q-18 0 -54 0.5t-55 0.5h-200l31 183h111q50 0 58 51v402h16q-6 1 -16 1v287q-13 68 -89 68h-111v164 l212 -1q64 0 97 1v252h154v-247q82 2 122 2v245h154v-252q79 -7 140 -22.5t113 -45t82.5 -78t36.5 -114.5zM952 351q0 36 -15 64t-37 46t-57.5 30.5t-65.5 18.5t-74 9t-69 3t-64.5 -1t-47.5 -1v-338q8 0 37 -0.5t48 -0.5t53 1.5t58.5 4t57 8.5t55.5 14t47.5 21t39.5 30 t24.5 40t9.5 51zM881 827q0 33 -12.5 58.5t-30.5 42t-48 28t-55 16.5t-61.5 8t-58 2.5t-54 -1t-39.5 -0.5v-307q5 0 34.5 -0.5t46.5 0t50 2t55 5.5t51.5 11t48.5 18.5t37 27t27 38.5t9 51z" /> <glyph glyph-name="file" unicode="" d="M1024 1024v472q22 -14 36 -28l408 -408q14 -14 28 -36h-472zM896 992q0 -40 28 -68t68 -28h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544z" /> <glyph glyph-name="file_text" unicode="" d="M1468 1060q14 -14 28 -36h-472v472q22 -14 36 -28zM992 896h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544q0 -40 28 -68t68 -28zM1152 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23z" /> <glyph glyph-name="sort_by_alphabet" unicode="" horiz-adv-x="1664" d="M1191 1128h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1572 -23 v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -11v-2l14 2q9 2 30 2h248v119h121zM1661 874v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162 l230 -662h70z" /> <glyph glyph-name="_329" unicode="" horiz-adv-x="1664" d="M1191 104h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1661 -150 v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162l230 -662h70zM1572 1001v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -10v-3l14 3q9 1 30 1h248 v119h121z" /> <glyph glyph-name="sort_by_attributes" unicode="" horiz-adv-x="1792" d="M736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1792 -32v-192q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832 q14 0 23 -9t9 -23zM1600 480v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1408 992v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1216 1504v-192q0 -14 -9 -23t-23 -9h-256 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23z" /> <glyph glyph-name="sort_by_attributes_alt" unicode="" horiz-adv-x="1792" d="M1216 -32v-192q0 -14 -9 -23t-23 -9h-256q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192 q14 0 23 -9t9 -23zM1408 480v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1600 992v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1792 1504v-192q0 -14 -9 -23t-23 -9h-832 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832q14 0 23 -9t9 -23z" /> <glyph glyph-name="sort_by_order" unicode="" d="M1346 223q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23 zM1486 165q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5 t82 -252.5zM1456 882v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165z" /> <glyph glyph-name="sort_by_order_alt" unicode="" d="M1346 1247q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9 t9 -23zM1456 -142v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165zM1486 1189q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13 q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5t82 -252.5z" /> <glyph glyph-name="_334" unicode="" horiz-adv-x="1664" d="M256 192q0 26 -19 45t-45 19q-27 0 -45.5 -19t-18.5 -45q0 -27 18.5 -45.5t45.5 -18.5q26 0 45 18.5t19 45.5zM416 704v-640q0 -26 -19 -45t-45 -19h-288q-26 0 -45 19t-19 45v640q0 26 19 45t45 19h288q26 0 45 -19t19 -45zM1600 704q0 -86 -55 -149q15 -44 15 -76 q3 -76 -43 -137q17 -56 0 -117q-15 -57 -54 -94q9 -112 -49 -181q-64 -76 -197 -78h-36h-76h-17q-66 0 -144 15.5t-121.5 29t-120.5 39.5q-123 43 -158 44q-26 1 -45 19.5t-19 44.5v641q0 25 18 43.5t43 20.5q24 2 76 59t101 121q68 87 101 120q18 18 31 48t17.5 48.5 t13.5 60.5q7 39 12.5 61t19.5 52t34 50q19 19 45 19q46 0 82.5 -10.5t60 -26t40 -40.5t24 -45t12 -50t5 -45t0.5 -39q0 -38 -9.5 -76t-19 -60t-27.5 -56q-3 -6 -10 -18t-11 -22t-8 -24h277q78 0 135 -57t57 -135z" /> <glyph glyph-name="_335" unicode="" horiz-adv-x="1664" d="M256 960q0 -26 -19 -45t-45 -19q-27 0 -45.5 19t-18.5 45q0 27 18.5 45.5t45.5 18.5q26 0 45 -18.5t19 -45.5zM416 448v640q0 26 -19 45t-45 19h-288q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h288q26 0 45 19t19 45zM1545 597q55 -61 55 -149q-1 -78 -57.5 -135 t-134.5 -57h-277q4 -14 8 -24t11 -22t10 -18q18 -37 27 -57t19 -58.5t10 -76.5q0 -24 -0.5 -39t-5 -45t-12 -50t-24 -45t-40 -40.5t-60 -26t-82.5 -10.5q-26 0 -45 19q-20 20 -34 50t-19.5 52t-12.5 61q-9 42 -13.5 60.5t-17.5 48.5t-31 48q-33 33 -101 120q-49 64 -101 121 t-76 59q-25 2 -43 20.5t-18 43.5v641q0 26 19 44.5t45 19.5q35 1 158 44q77 26 120.5 39.5t121.5 29t144 15.5h17h76h36q133 -2 197 -78q58 -69 49 -181q39 -37 54 -94q17 -61 0 -117q46 -61 43 -137q0 -32 -15 -76z" /> <glyph glyph-name="youtube_sign" unicode="" d="M919 233v157q0 50 -29 50q-17 0 -33 -16v-224q16 -16 33 -16q29 0 29 49zM1103 355h66v34q0 51 -33 51t-33 -51v-34zM532 621v-70h-80v-423h-74v423h-78v70h232zM733 495v-367h-67v40q-39 -45 -76 -45q-33 0 -42 28q-6 17 -6 54v290h66v-270q0 -24 1 -26q1 -15 15 -15 q20 0 42 31v280h67zM985 384v-146q0 -52 -7 -73q-12 -42 -53 -42q-35 0 -68 41v-36h-67v493h67v-161q32 40 68 40q41 0 53 -42q7 -21 7 -74zM1236 255v-9q0 -29 -2 -43q-3 -22 -15 -40q-27 -40 -80 -40q-52 0 -81 38q-21 27 -21 86v129q0 59 20 86q29 38 80 38t78 -38 q21 -29 21 -86v-76h-133v-65q0 -51 34 -51q24 0 30 26q0 1 0.5 7t0.5 16.5v21.5h68zM785 1079v-156q0 -51 -32 -51t-32 51v156q0 52 32 52t32 -52zM1318 366q0 177 -19 260q-10 44 -43 73.5t-76 34.5q-136 15 -412 15q-275 0 -411 -15q-44 -5 -76.5 -34.5t-42.5 -73.5 q-20 -87 -20 -260q0 -176 20 -260q10 -43 42.5 -73t75.5 -35q137 -15 412 -15t412 15q43 5 75.5 35t42.5 73q20 84 20 260zM563 1017l90 296h-75l-51 -195l-53 195h-78q7 -23 23 -69l24 -69q35 -103 46 -158v-201h74v201zM852 936v130q0 58 -21 87q-29 38 -78 38 q-51 0 -78 -38q-21 -29 -21 -87v-130q0 -58 21 -87q27 -38 78 -38q49 0 78 38q21 27 21 87zM1033 816h67v370h-67v-283q-22 -31 -42 -31q-15 0 -16 16q-1 2 -1 26v272h-67v-293q0 -37 6 -55q11 -27 43 -27q36 0 77 45v-40zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5 h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="youtube" unicode="" d="M971 292v-211q0 -67 -39 -67q-23 0 -45 22v301q22 22 45 22q39 0 39 -67zM1309 291v-46h-90v46q0 68 45 68t45 -68zM343 509h107v94h-312v-94h105v-569h100v569zM631 -60h89v494h-89v-378q-30 -42 -57 -42q-18 0 -21 21q-1 3 -1 35v364h-89v-391q0 -49 8 -73 q12 -37 58 -37q48 0 102 61v-54zM1060 88v197q0 73 -9 99q-17 56 -71 56q-50 0 -93 -54v217h-89v-663h89v48q45 -55 93 -55q54 0 71 55q9 27 9 100zM1398 98v13h-91q0 -51 -2 -61q-7 -36 -40 -36q-46 0 -46 69v87h179v103q0 79 -27 116q-39 51 -106 51q-68 0 -107 -51 q-28 -37 -28 -116v-173q0 -79 29 -116q39 -51 108 -51q72 0 108 53q18 27 21 54q2 9 2 58zM790 1011v210q0 69 -43 69t-43 -69v-210q0 -70 43 -70t43 70zM1509 260q0 -234 -26 -350q-14 -59 -58 -99t-102 -46q-184 -21 -555 -21t-555 21q-58 6 -102.5 46t-57.5 99 q-26 112 -26 350q0 234 26 350q14 59 58 99t103 47q183 20 554 20t555 -20q58 -7 102.5 -47t57.5 -99q26 -112 26 -350zM511 1536h102l-121 -399v-271h-100v271q-14 74 -61 212q-37 103 -65 187h106l71 -263zM881 1203v-175q0 -81 -28 -118q-38 -51 -106 -51q-67 0 -105 51 q-28 38 -28 118v175q0 80 28 117q38 51 105 51q68 0 106 -51q28 -37 28 -117zM1216 1365v-499h-91v55q-53 -62 -103 -62q-46 0 -59 37q-8 24 -8 75v394h91v-367q0 -33 1 -35q3 -22 21 -22q27 0 57 43v381h91z" /> <glyph glyph-name="xing" unicode="" horiz-adv-x="1408" d="M597 869q-10 -18 -257 -456q-27 -46 -65 -46h-239q-21 0 -31 17t0 36l253 448q1 0 0 1l-161 279q-12 22 -1 37q9 15 32 15h239q40 0 66 -45zM1403 1511q11 -16 0 -37l-528 -934v-1l336 -615q11 -20 1 -37q-10 -15 -32 -15h-239q-42 0 -66 45l-339 622q18 32 531 942 q25 45 64 45h241q22 0 31 -15z" /> <glyph glyph-name="xing_sign" unicode="" d="M685 771q0 1 -126 222q-21 34 -52 34h-184q-18 0 -26 -11q-7 -12 1 -29l125 -216v-1l-196 -346q-9 -14 0 -28q8 -13 24 -13h185q31 0 50 36zM1309 1268q-7 12 -24 12h-187q-30 0 -49 -35l-411 -729q1 -2 262 -481q20 -35 52 -35h184q18 0 25 12q8 13 -1 28l-260 476v1 l409 723q8 16 0 28zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="youtube_play" unicode="" horiz-adv-x="1792" d="M711 408l484 250l-484 253v-503zM896 1270q168 0 324.5 -4.5t229.5 -9.5l73 -4q1 0 17 -1.5t23 -3t23.5 -4.5t28.5 -8t28 -13t31 -19.5t29 -26.5q6 -6 15.5 -18.5t29 -58.5t26.5 -101q8 -64 12.5 -136.5t5.5 -113.5v-40v-136q1 -145 -18 -290q-7 -55 -25 -99.5t-32 -61.5 l-14 -17q-14 -15 -29 -26.5t-31 -19t-28 -12.5t-28.5 -8t-24 -4.5t-23 -3t-16.5 -1.5q-251 -19 -627 -19q-207 2 -359.5 6.5t-200.5 7.5l-49 4l-36 4q-36 5 -54.5 10t-51 21t-56.5 41q-6 6 -15.5 18.5t-29 58.5t-26.5 101q-8 64 -12.5 136.5t-5.5 113.5v40v136 q-1 145 18 290q7 55 25 99.5t32 61.5l14 17q14 15 29 26.5t31 19.5t28 13t28.5 8t23.5 4.5t23 3t17 1.5q251 18 627 18z" /> <glyph glyph-name="dropbox" unicode="" horiz-adv-x="1792" d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" /> <glyph glyph-name="stackexchange" unicode="" d="M1289 -96h-1118v480h-160v-640h1438v640h-160v-480zM347 428l33 157l783 -165l-33 -156zM450 802l67 146l725 -339l-67 -145zM651 1158l102 123l614 -513l-102 -123zM1048 1536l477 -641l-128 -96l-477 641zM330 65v159h800v-159h-800z" /> <glyph glyph-name="instagram" unicode="" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1162 640q0 -164 -115 -279t-279 -115t-279 115t-115 279t115 279t279 115t279 -115t115 -279zM1270 1050q0 -38 -27 -65t-65 -27t-65 27t-27 65t27 65t65 27t65 -27t27 -65zM768 1270 q-7 0 -76.5 0.5t-105.5 0t-96.5 -3t-103 -10t-71.5 -18.5q-50 -20 -88 -58t-58 -88q-11 -29 -18.5 -71.5t-10 -103t-3 -96.5t0 -105.5t0.5 -76.5t-0.5 -76.5t0 -105.5t3 -96.5t10 -103t18.5 -71.5q20 -50 58 -88t88 -58q29 -11 71.5 -18.5t103 -10t96.5 -3t105.5 0t76.5 0.5 t76.5 -0.5t105.5 0t96.5 3t103 10t71.5 18.5q50 20 88 58t58 88q11 29 18.5 71.5t10 103t3 96.5t0 105.5t-0.5 76.5t0.5 76.5t0 105.5t-3 96.5t-10 103t-18.5 71.5q-20 50 -58 88t-88 58q-29 11 -71.5 18.5t-103 10t-96.5 3t-105.5 0t-76.5 -0.5zM1536 640q0 -229 -5 -317 q-10 -208 -124 -322t-322 -124q-88 -5 -317 -5t-317 5q-208 10 -322 124t-124 322q-5 88 -5 317t5 317q10 208 124 322t322 124q88 5 317 5t317 -5q208 -10 322 -124t124 -322q5 -88 5 -317z" /> <glyph glyph-name="flickr" unicode="" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" /> <glyph glyph-name="adn" unicode="" d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="f171" unicode="" horiz-adv-x="1408" d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18 t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5 t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" /> <glyph glyph-name="bitbucket_sign" unicode="" d="M848 666q0 43 -41 66t-77 1q-43 -20 -42.5 -72.5t43.5 -70.5q39 -23 81 4t36 72zM928 682q8 -66 -36 -121t-110 -61t-119 40t-56 113q-2 49 25.5 93t72.5 64q70 31 141.5 -10t81.5 -118zM1100 1073q-20 -21 -53.5 -34t-53 -16t-63.5 -8q-155 -20 -324 0q-44 6 -63 9.5 t-52.5 16t-54.5 32.5q13 19 36 31t40 15.5t47 8.5q198 35 408 1q33 -5 51 -8.5t43 -16t39 -31.5zM1142 327q0 7 5.5 26.5t3 32t-17.5 16.5q-161 -106 -365 -106t-366 106l-12 -6l-5 -12q26 -154 41 -210q47 -81 204 -108q249 -46 428 53q34 19 49 51.5t22.5 85.5t12.5 71z M1272 1020q9 53 -8 75q-43 55 -155 88q-216 63 -487 36q-132 -12 -226 -46q-38 -15 -59.5 -25t-47 -34t-29.5 -54q8 -68 19 -138t29 -171t24 -137q1 -5 5 -31t7 -36t12 -27t22 -28q105 -80 284 -100q259 -28 440 63q24 13 39.5 23t31 29t19.5 40q48 267 80 473zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="tumblr" unicode="" horiz-adv-x="1024" d="M944 207l80 -237q-23 -35 -111 -66t-177 -32q-104 -2 -190.5 26t-142.5 74t-95 106t-55.5 120t-16.5 118v544h-168v215q72 26 129 69.5t91 90t58 102t34 99t15 88.5q1 5 4.5 8.5t7.5 3.5h244v-424h333v-252h-334v-518q0 -30 6.5 -56t22.5 -52.5t49.5 -41.5t81.5 -14 q78 2 134 29z" /> <glyph glyph-name="tumblr_sign" unicode="" d="M1136 75l-62 183q-44 -22 -103 -22q-36 -1 -62 10.5t-38.5 31.5t-17.5 40.5t-5 43.5v398h257v194h-256v326h-188q-8 0 -9 -10q-5 -44 -17.5 -87t-39 -95t-77 -95t-118.5 -68v-165h130v-418q0 -57 21.5 -115t65 -111t121 -85.5t176.5 -30.5q69 1 136.5 25t85.5 50z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="long_arrow_down" unicode="" horiz-adv-x="768" d="M765 237q8 -19 -5 -35l-350 -384q-10 -10 -23 -10q-14 0 -24 10l-355 384q-13 16 -5 35q9 19 29 19h224v1248q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1248h224q21 0 29 -19z" /> <glyph glyph-name="long_arrow_up" unicode="" horiz-adv-x="768" d="M765 1043q-9 -19 -29 -19h-224v-1248q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1248h-224q-21 0 -29 19t5 35l350 384q10 10 23 10q14 0 24 -10l355 -384q13 -16 5 -35z" /> <glyph glyph-name="long_arrow_left" unicode="" horiz-adv-x="1792" d="M1792 736v-192q0 -14 -9 -23t-23 -9h-1248v-224q0 -21 -19 -29t-35 5l-384 350q-10 10 -10 23q0 14 10 24l384 354q16 14 35 6q19 -9 19 -29v-224h1248q14 0 23 -9t9 -23z" /> <glyph glyph-name="long_arrow_right" unicode="" horiz-adv-x="1792" d="M1728 643q0 -14 -10 -24l-384 -354q-16 -14 -35 -6q-19 9 -19 29v224h-1248q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h1248v224q0 21 19 29t35 -5l384 -350q10 -10 10 -23z" /> <glyph glyph-name="apple" unicode="" horiz-adv-x="1408" d="M1393 321q-39 -125 -123 -250q-129 -196 -257 -196q-49 0 -140 32q-86 32 -151 32q-61 0 -142 -33q-81 -34 -132 -34q-152 0 -301 259q-147 261 -147 503q0 228 113 374q113 144 284 144q72 0 177 -30q104 -30 138 -30q45 0 143 34q102 34 173 34q119 0 213 -65 q52 -36 104 -100q-79 -67 -114 -118q-65 -94 -65 -207q0 -124 69 -223t158 -126zM1017 1494q0 -61 -29 -136q-30 -75 -93 -138q-54 -54 -108 -72q-37 -11 -104 -17q3 149 78 257q74 107 250 148q1 -3 2.5 -11t2.5 -11q0 -4 0.5 -10t0.5 -10z" /> <glyph glyph-name="windows" unicode="" horiz-adv-x="1664" d="M682 530v-651l-682 94v557h682zM682 1273v-659h-682v565zM1664 530v-786l-907 125v661h907zM1664 1408v-794h-907v669z" /> <glyph glyph-name="android" unicode="" horiz-adv-x="1408" d="M493 1053q16 0 27.5 11.5t11.5 27.5t-11.5 27.5t-27.5 11.5t-27 -11.5t-11 -27.5t11 -27.5t27 -11.5zM915 1053q16 0 27 11.5t11 27.5t-11 27.5t-27 11.5t-27.5 -11.5t-11.5 -27.5t11.5 -27.5t27.5 -11.5zM103 869q42 0 72 -30t30 -72v-430q0 -43 -29.5 -73t-72.5 -30 t-73 30t-30 73v430q0 42 30 72t73 30zM1163 850v-666q0 -46 -32 -78t-77 -32h-75v-227q0 -43 -30 -73t-73 -30t-73 30t-30 73v227h-138v-227q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73l-1 227h-74q-46 0 -78 32t-32 78v666h918zM931 1255q107 -55 171 -153.5t64 -215.5 h-925q0 117 64 215.5t172 153.5l-71 131q-7 13 5 20q13 6 20 -6l72 -132q95 42 201 42t201 -42l72 132q7 12 20 6q12 -7 5 -20zM1408 767v-430q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73v430q0 43 30 72.5t72 29.5q43 0 73 -29.5t30 -72.5z" /> <glyph glyph-name="linux" unicode="" d="M663 1125q-11 -1 -15.5 -10.5t-8.5 -9.5q-5 -1 -5 5q0 12 19 15h10zM750 1111q-4 -1 -11.5 6.5t-17.5 4.5q24 11 32 -2q3 -6 -3 -9zM399 684q-4 1 -6 -3t-4.5 -12.5t-5.5 -13.5t-10 -13q-10 -11 -1 -12q4 -1 12.5 7t12.5 18q1 3 2 7t2 6t1.5 4.5t0.5 4v3t-1 2.5t-3 2z M1254 325q0 18 -55 42q4 15 7.5 27.5t5 26t3 21.5t0.5 22.5t-1 19.5t-3.5 22t-4 20.5t-5 25t-5.5 26.5q-10 48 -47 103t-72 75q24 -20 57 -83q87 -162 54 -278q-11 -40 -50 -42q-31 -4 -38.5 18.5t-8 83.5t-11.5 107q-9 39 -19.5 69t-19.5 45.5t-15.5 24.5t-13 15t-7.5 7 q-14 62 -31 103t-29.5 56t-23.5 33t-15 40q-4 21 6 53.5t4.5 49.5t-44.5 25q-15 3 -44.5 18t-35.5 16q-8 1 -11 26t8 51t36 27q37 3 51 -30t4 -58q-11 -19 -2 -26.5t30 -0.5q13 4 13 36v37q-5 30 -13.5 50t-21 30.5t-23.5 15t-27 7.5q-107 -8 -89 -134q0 -15 -1 -15 q-9 9 -29.5 10.5t-33 -0.5t-15.5 5q1 57 -16 90t-45 34q-27 1 -41.5 -27.5t-16.5 -59.5q-1 -15 3.5 -37t13 -37.5t15.5 -13.5q10 3 16 14q4 9 -7 8q-7 0 -15.5 14.5t-9.5 33.5q-1 22 9 37t34 14q17 0 27 -21t9.5 -39t-1.5 -22q-22 -15 -31 -29q-8 -12 -27.5 -23.5 t-20.5 -12.5q-13 -14 -15.5 -27t7.5 -18q14 -8 25 -19.5t16 -19t18.5 -13t35.5 -6.5q47 -2 102 15q2 1 23 7t34.5 10.5t29.5 13t21 17.5q9 14 20 8q5 -3 6.5 -8.5t-3 -12t-16.5 -9.5q-20 -6 -56.5 -21.5t-45.5 -19.5q-44 -19 -70 -23q-25 -5 -79 2q-10 2 -9 -2t17 -19 q25 -23 67 -22q17 1 36 7t36 14t33.5 17.5t30 17t24.5 12t17.5 2.5t8.5 -11q0 -2 -1 -4.5t-4 -5t-6 -4.5t-8.5 -5t-9 -4.5t-10 -5t-9.5 -4.5q-28 -14 -67.5 -44t-66.5 -43t-49 -1q-21 11 -63 73q-22 31 -25 22q-1 -3 -1 -10q0 -25 -15 -56.5t-29.5 -55.5t-21 -58t11.5 -63 q-23 -6 -62.5 -90t-47.5 -141q-2 -18 -1.5 -69t-5.5 -59q-8 -24 -29 -3q-32 31 -36 94q-2 28 4 56q4 19 -1 18q-2 -1 -4 -5q-36 -65 10 -166q5 -12 25 -28t24 -20q20 -23 104 -90.5t93 -76.5q16 -15 17.5 -38t-14 -43t-45.5 -23q8 -15 29 -44.5t28 -54t7 -70.5q46 24 7 92 q-4 8 -10.5 16t-9.5 12t-2 6q3 5 13 9.5t20 -2.5q46 -52 166 -36q133 15 177 87q23 38 34 30q12 -6 10 -52q-1 -25 -23 -92q-9 -23 -6 -37.5t24 -15.5q3 19 14.5 77t13.5 90q2 21 -6.5 73.5t-7.5 97t23 70.5q15 18 51 18q1 37 34.5 53t72.5 10.5t60 -22.5zM626 1152 q3 17 -2.5 30t-11.5 15q-9 2 -9 -7q2 -5 5 -6q10 0 7 -15q-3 -20 8 -20q3 0 3 3zM1045 955q-2 8 -6.5 11.5t-13 5t-14.5 5.5q-5 3 -9.5 8t-7 8t-5.5 6.5t-4 4t-4 -1.5q-14 -16 7 -43.5t39 -31.5q9 -1 14.5 8t3.5 20zM867 1168q0 11 -5 19.5t-11 12.5t-9 3q-6 0 -8 -2t0 -4 t5 -3q14 -4 18 -31q0 -3 8 2q2 2 2 3zM921 1401q0 2 -2.5 5t-9 7t-9.5 6q-15 15 -24 15q-9 -1 -11.5 -7.5t-1 -13t-0.5 -12.5q-1 -4 -6 -10.5t-6 -9t3 -8.5q4 -3 8 0t11 9t15 9q1 1 9 1t15 2t9 7zM1486 60q20 -12 31 -24.5t12 -24t-2.5 -22.5t-15.5 -22t-23.5 -19.5 t-30 -18.5t-31.5 -16.5t-32 -15.5t-27 -13q-38 -19 -85.5 -56t-75.5 -64q-17 -16 -68 -19.5t-89 14.5q-18 9 -29.5 23.5t-16.5 25.5t-22 19.5t-47 9.5q-44 1 -130 1q-19 0 -57 -1.5t-58 -2.5q-44 -1 -79.5 -15t-53.5 -30t-43.5 -28.5t-53.5 -11.5q-29 1 -111 31t-146 43 q-19 4 -51 9.5t-50 9t-39.5 9.5t-33.5 14.5t-17 19.5q-10 23 7 66.5t18 54.5q1 16 -4 40t-10 42.5t-4.5 36.5t10.5 27q14 12 57 14t60 12q30 18 42 35t12 51q21 -73 -32 -106q-32 -20 -83 -15q-34 3 -43 -10q-13 -15 5 -57q2 -6 8 -18t8.5 -18t4.5 -17t1 -22q0 -15 -17 -49 t-14 -48q3 -17 37 -26q20 -6 84.5 -18.5t99.5 -20.5q24 -6 74 -22t82.5 -23t55.5 -4q43 6 64.5 28t23 48t-7.5 58.5t-19 52t-20 36.5q-121 190 -169 242q-68 74 -113 40q-11 -9 -15 15q-3 16 -2 38q1 29 10 52t24 47t22 42q8 21 26.5 72t29.5 78t30 61t39 54 q110 143 124 195q-12 112 -16 310q-2 90 24 151.5t106 104.5q39 21 104 21q53 1 106 -13.5t89 -41.5q57 -42 91.5 -121.5t29.5 -147.5q-5 -95 30 -214q34 -113 133 -218q55 -59 99.5 -163t59.5 -191q8 -49 5 -84.5t-12 -55.5t-20 -22q-10 -2 -23.5 -19t-27 -35.5 t-40.5 -33.5t-61 -14q-18 1 -31.5 5t-22.5 13.5t-13.5 15.5t-11.5 20.5t-9 19.5q-22 37 -41 30t-28 -49t7 -97q20 -70 1 -195q-10 -65 18 -100.5t73 -33t85 35.5q59 49 89.5 66.5t103.5 42.5q53 18 77 36.5t18.5 34.5t-25 28.5t-51.5 23.5q-33 11 -49.5 48t-15 72.5 t15.5 47.5q1 -31 8 -56.5t14.5 -40.5t20.5 -28.5t21 -19t21.5 -13t16.5 -9.5z" /> <glyph glyph-name="dribble" unicode="" d="M1024 36q-42 241 -140 498h-2l-2 -1q-16 -6 -43 -16.5t-101 -49t-137 -82t-131 -114.5t-103 -148l-15 11q184 -150 418 -150q132 0 256 52zM839 643q-21 49 -53 111q-311 -93 -673 -93q-1 -7 -1 -21q0 -124 44 -236.5t124 -201.5q50 89 123.5 166.5t142.5 124.5t130.5 81 t99.5 48l37 13q4 1 13 3.5t13 4.5zM732 855q-120 213 -244 378q-138 -65 -234 -186t-128 -272q302 0 606 80zM1416 536q-210 60 -409 29q87 -239 128 -469q111 75 185 189.5t96 250.5zM611 1277q-1 0 -2 -1q1 1 2 1zM1201 1132q-185 164 -433 164q-76 0 -155 -19 q131 -170 246 -382q69 26 130 60.5t96.5 61.5t65.5 57t37.5 40.5zM1424 647q-3 232 -149 410l-1 -1q-9 -12 -19 -24.5t-43.5 -44.5t-71 -60.5t-100 -65t-131.5 -64.5q25 -53 44 -95q2 -5 6.5 -17t7.5 -17q36 5 74.5 7t73.5 2t69 -1.5t64 -4t56.5 -5.5t48 -6.5t36.5 -6 t25 -4.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="skype" unicode="" d="M1173 473q0 50 -19.5 91.5t-48.5 68.5t-73 49t-82.5 34t-87.5 23l-104 24q-30 7 -44 10.5t-35 11.5t-30 16t-16.5 21t-7.5 30q0 77 144 77q43 0 77 -12t54 -28.5t38 -33.5t40 -29t48 -12q47 0 75.5 32t28.5 77q0 55 -56 99.5t-142 67.5t-182 23q-68 0 -132 -15.5 t-119.5 -47t-89 -87t-33.5 -128.5q0 -61 19 -106.5t56 -75.5t80 -48.5t103 -32.5l146 -36q90 -22 112 -36q32 -20 32 -60q0 -39 -40 -64.5t-105 -25.5q-51 0 -91.5 16t-65 38.5t-45.5 45t-46 38.5t-54 16q-50 0 -75.5 -30t-25.5 -75q0 -92 122 -157.5t291 -65.5 q73 0 140 18.5t122.5 53.5t88.5 93.5t33 131.5zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5q-130 0 -234 80q-77 -16 -150 -16q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5q0 73 16 150q-80 104 -80 234q0 159 112.5 271.5t271.5 112.5q130 0 234 -80 q77 16 150 16q143 0 273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -73 -16 -150q80 -104 80 -234z" /> <glyph glyph-name="foursquare" unicode="" horiz-adv-x="1280" d="M1000 1102l37 194q5 23 -9 40t-35 17h-712q-23 0 -38.5 -17t-15.5 -37v-1101q0 -7 6 -1l291 352q23 26 38 33.5t48 7.5h239q22 0 37 14.5t18 29.5q24 130 37 191q4 21 -11.5 40t-36.5 19h-294q-29 0 -48 19t-19 48v42q0 29 19 47.5t48 18.5h346q18 0 35 13.5t20 29.5z M1227 1324q-15 -73 -53.5 -266.5t-69.5 -350t-35 -173.5q-6 -22 -9 -32.5t-14 -32.5t-24.5 -33t-38.5 -21t-58 -10h-271q-13 0 -22 -10q-8 -9 -426 -494q-22 -25 -58.5 -28.5t-48.5 5.5q-55 22 -55 98v1410q0 55 38 102.5t120 47.5h888q95 0 127 -53t10 -159zM1227 1324 l-158 -790q4 17 35 173.5t69.5 350t53.5 266.5z" /> <glyph glyph-name="trello" unicode="" d="M704 192v1024q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-1024q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1376 576v640q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-640q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408 q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" /> <glyph glyph-name="female" unicode="" horiz-adv-x="1280" d="M1280 480q0 -40 -28 -68t-68 -28q-51 0 -80 43l-227 341h-45v-132l247 -411q9 -15 9 -33q0 -26 -19 -45t-45 -19h-192v-272q0 -46 -33 -79t-79 -33h-160q-46 0 -79 33t-33 79v272h-192q-26 0 -45 19t-19 45q0 18 9 33l247 411v132h-45l-227 -341q-29 -43 -80 -43 q-40 0 -68 28t-28 68q0 29 16 53l256 384q73 107 176 107h384q103 0 176 -107l256 -384q16 -24 16 -53zM864 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" /> <glyph glyph-name="male" unicode="" horiz-adv-x="1024" d="M1024 832v-416q0 -40 -28 -68t-68 -28t-68 28t-28 68v352h-64v-912q0 -46 -33 -79t-79 -33t-79 33t-33 79v464h-64v-464q0 -46 -33 -79t-79 -33t-79 33t-33 79v912h-64v-352q0 -40 -28 -68t-68 -28t-68 28t-28 68v416q0 80 56 136t136 56h640q80 0 136 -56t56 -136z M736 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" /> <glyph glyph-name="gittip" unicode="" d="M773 234l350 473q16 22 24.5 59t-6 85t-61.5 79q-40 26 -83 25.5t-73.5 -17.5t-54.5 -45q-36 -40 -96 -40q-59 0 -95 40q-24 28 -54.5 45t-73.5 17.5t-84 -25.5q-46 -31 -60.5 -79t-6 -85t24.5 -59zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="sun" unicode="" horiz-adv-x="1792" d="M1472 640q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5zM1748 363q-4 -15 -20 -20l-292 -96v-306q0 -16 -13 -26q-15 -10 -29 -4 l-292 94l-180 -248q-10 -13 -26 -13t-26 13l-180 248l-292 -94q-14 -6 -29 4q-13 10 -13 26v306l-292 96q-16 5 -20 20q-5 17 4 29l180 248l-180 248q-9 13 -4 29q4 15 20 20l292 96v306q0 16 13 26q15 10 29 4l292 -94l180 248q9 12 26 12t26 -12l180 -248l292 94 q14 6 29 -4q13 -10 13 -26v-306l292 -96q16 -5 20 -20q5 -16 -4 -29l-180 -248l180 -248q9 -12 4 -29z" /> <glyph glyph-name="_366" unicode="" d="M1262 233q-54 -9 -110 -9q-182 0 -337 90t-245 245t-90 337q0 192 104 357q-201 -60 -328.5 -229t-127.5 -384q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51q144 0 273.5 61.5t220.5 171.5zM1465 318q-94 -203 -283.5 -324.5t-413.5 -121.5q-156 0 -298 61 t-245 164t-164 245t-61 298q0 153 57.5 292.5t156 241.5t235.5 164.5t290 68.5q44 2 61 -39q18 -41 -15 -72q-86 -78 -131.5 -181.5t-45.5 -218.5q0 -148 73 -273t198 -198t273 -73q118 0 228 51q41 18 72 -13q14 -14 17.5 -34t-4.5 -38z" /> <glyph glyph-name="archive" unicode="" horiz-adv-x="1792" d="M1088 704q0 26 -19 45t-45 19h-256q-26 0 -45 -19t-19 -45t19 -45t45 -19h256q26 0 45 19t19 45zM1664 896v-960q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v960q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1728 1344v-256q0 -26 -19 -45t-45 -19h-1536 q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1536q26 0 45 -19t19 -45z" /> <glyph glyph-name="bug" unicode="" horiz-adv-x="1664" d="M1632 576q0 -26 -19 -45t-45 -19h-224q0 -171 -67 -290l208 -209q19 -19 19 -45t-19 -45q-18 -19 -45 -19t-45 19l-198 197q-5 -5 -15 -13t-42 -28.5t-65 -36.5t-82 -29t-97 -13v896h-128v-896q-51 0 -101.5 13.5t-87 33t-66 39t-43.5 32.5l-15 14l-183 -207 q-20 -21 -48 -21q-24 0 -43 16q-19 18 -20.5 44.5t15.5 46.5l202 227q-58 114 -58 274h-224q-26 0 -45 19t-19 45t19 45t45 19h224v294l-173 173q-19 19 -19 45t19 45t45 19t45 -19l173 -173h844l173 173q19 19 45 19t45 -19t19 -45t-19 -45l-173 -173v-294h224q26 0 45 -19 t19 -45zM1152 1152h-640q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5z" /> <glyph glyph-name="vk" unicode="" horiz-adv-x="1920" d="M1917 1016q23 -64 -150 -294q-24 -32 -65 -85q-40 -51 -55 -72t-30.5 -49.5t-12 -42t13 -34.5t32.5 -43t57 -53q4 -2 5 -4q141 -131 191 -221q3 -5 6.5 -12.5t7 -26.5t-0.5 -34t-25 -27.5t-59 -12.5l-256 -4q-24 -5 -56 5t-52 22l-20 12q-30 21 -70 64t-68.5 77.5t-61 58 t-56.5 15.5q-3 -1 -8 -3.5t-17 -14.5t-21.5 -29.5t-17 -52t-6.5 -77.5q0 -15 -3.5 -27.5t-7.5 -18.5l-4 -5q-18 -19 -53 -22h-115q-71 -4 -146 16.5t-131.5 53t-103 66t-70.5 57.5l-25 24q-10 10 -27.5 30t-71.5 91t-106 151t-122.5 211t-130.5 272q-6 16 -6 27t3 16l4 6 q15 19 57 19l274 2q12 -2 23 -6.5t16 -8.5l5 -3q16 -11 24 -32q20 -50 46 -103.5t41 -81.5l16 -29q29 -60 56 -104t48.5 -68.5t41.5 -38.5t34 -14t27 5q2 1 5 5t12 22t13.5 47t9.5 81t0 125q-2 40 -9 73t-14 46l-6 12q-25 34 -85 43q-13 2 5 24q16 19 38 30q53 26 239 24 q82 -1 135 -13q20 -5 33.5 -13.5t20.5 -24t10.5 -32t3.5 -45.5t-1 -55t-2.5 -70.5t-1.5 -82.5q0 -11 -1 -42t-0.5 -48t3.5 -40.5t11.5 -39t22.5 -24.5q8 -2 17 -4t26 11t38 34.5t52 67t68 107.5q60 104 107 225q4 10 10 17.5t11 10.5l4 3l5 2.5t13 3t20 0.5l288 2 q39 5 64 -2.5t31 -16.5z" /> <glyph glyph-name="weibo" unicode="" horiz-adv-x="1792" d="M675 252q21 34 11 69t-45 50q-34 14 -73 1t-60 -46q-22 -34 -13 -68.5t43 -50.5t74.5 -2.5t62.5 47.5zM769 373q8 13 3.5 26.5t-17.5 18.5q-14 5 -28.5 -0.5t-21.5 -18.5q-17 -31 13 -45q14 -5 29 0.5t22 18.5zM943 266q-45 -102 -158 -150t-224 -12 q-107 34 -147.5 126.5t6.5 187.5q47 93 151.5 139t210.5 19q111 -29 158.5 -119.5t2.5 -190.5zM1255 426q-9 96 -89 170t-208.5 109t-274.5 21q-223 -23 -369.5 -141.5t-132.5 -264.5q9 -96 89 -170t208.5 -109t274.5 -21q223 23 369.5 141.5t132.5 264.5zM1563 422 q0 -68 -37 -139.5t-109 -137t-168.5 -117.5t-226 -83t-270.5 -31t-275 33.5t-240.5 93t-171.5 151t-65 199.5q0 115 69.5 245t197.5 258q169 169 341.5 236t246.5 -7q65 -64 20 -209q-4 -14 -1 -20t10 -7t14.5 0.5t13.5 3.5l6 2q139 59 246 59t153 -61q45 -63 0 -178 q-2 -13 -4.5 -20t4.5 -12.5t12 -7.5t17 -6q57 -18 103 -47t80 -81.5t34 -116.5zM1489 1046q42 -47 54.5 -108.5t-6.5 -117.5q-8 -23 -29.5 -34t-44.5 -4q-23 8 -34 29.5t-4 44.5q20 63 -24 111t-107 35q-24 -5 -45 8t-25 37q-5 24 8 44.5t37 25.5q60 13 119 -5.5t101 -65.5z M1670 1209q87 -96 112.5 -222.5t-13.5 -241.5q-9 -27 -34 -40t-52 -4t-40 34t-5 52q28 82 10 172t-80 158q-62 69 -148 95.5t-173 8.5q-28 -6 -52 9.5t-30 43.5t9.5 51.5t43.5 29.5q123 26 244 -11.5t208 -134.5z" /> <glyph glyph-name="renren" unicode="" d="M1133 -34q-171 -94 -368 -94q-196 0 -367 94q138 87 235.5 211t131.5 268q35 -144 132.5 -268t235.5 -211zM638 1394v-485q0 -252 -126.5 -459.5t-330.5 -306.5q-181 215 -181 495q0 187 83.5 349.5t229.5 269.5t325 137zM1536 638q0 -280 -181 -495 q-204 99 -330.5 306.5t-126.5 459.5v485q179 -30 325 -137t229.5 -269.5t83.5 -349.5z" /> <glyph glyph-name="_372" unicode="" horiz-adv-x="1408" d="M1402 433q-32 -80 -76 -138t-91 -88.5t-99 -46.5t-101.5 -14.5t-96.5 8.5t-86.5 22t-69.5 27.5t-46 22.5l-17 10q-113 -228 -289.5 -359.5t-384.5 -132.5q-19 0 -32 13t-13 32t13 31.5t32 12.5q173 1 322.5 107.5t251.5 294.5q-36 -14 -72 -23t-83 -13t-91 2.5t-93 28.5 t-92 59t-84.5 100t-74.5 146q114 47 214 57t167.5 -7.5t124.5 -56.5t88.5 -77t56.5 -82q53 131 79 291q-7 -1 -18 -2.5t-46.5 -2.5t-69.5 0.5t-81.5 10t-88.5 23t-84 42.5t-75 65t-54.5 94.5t-28.5 127.5q70 28 133.5 36.5t112.5 -1t92 -30t73.5 -50t56 -61t42 -63t27.5 -56 t16 -39.5l4 -16q12 122 12 195q-8 6 -21.5 16t-49 44.5t-63.5 71.5t-54 93t-33 112.5t12 127t70 138.5q73 -25 127.5 -61.5t84.5 -76.5t48 -85t20.5 -89t-0.5 -85.5t-13 -76.5t-19 -62t-17 -42l-7 -15q1 -4 1 -50t-1 -72q3 7 10 18.5t30.5 43t50.5 58t71 55.5t91.5 44.5 t112 14.5t132.5 -24q-2 -78 -21.5 -141.5t-50 -104.5t-69.5 -71.5t-81.5 -45.5t-84.5 -24t-80 -9.5t-67.5 1t-46.5 4.5l-17 3q-23 -147 -73 -283q6 7 18 18.5t49.5 41t77.5 52.5t99.5 42t117.5 20t129 -23.5t137 -77.5z" /> <glyph glyph-name="stack_exchange" unicode="" horiz-adv-x="1280" d="M1259 283v-66q0 -85 -57.5 -144.5t-138.5 -59.5h-57l-260 -269v269h-529q-81 0 -138.5 59.5t-57.5 144.5v66h1238zM1259 609v-255h-1238v255h1238zM1259 937v-255h-1238v255h1238zM1259 1077v-67h-1238v67q0 84 57.5 143.5t138.5 59.5h846q81 0 138.5 -59.5t57.5 -143.5z " /> <glyph glyph-name="_374" unicode="" d="M1152 640q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="arrow_circle_alt_left" unicode="" d="M1152 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-192q0 -14 -9 -23t-23 -9q-12 0 -24 10l-319 319q-9 9 -9 23t9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h352q13 0 22.5 -9.5t9.5 -22.5zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="_376" unicode="" d="M1024 960v-640q0 -26 -19 -45t-45 -19q-20 0 -37 12l-448 320q-27 19 -27 52t27 52l448 320q17 12 37 12q26 0 45 -19t19 -45zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="dot_circle_alt" unicode="" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5 t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="_378" unicode="" horiz-adv-x="1664" d="M1023 349l102 -204q-58 -179 -210 -290t-339 -111q-156 0 -288.5 77.5t-210 210t-77.5 288.5q0 181 104.5 330t274.5 211l17 -131q-122 -54 -195 -165.5t-73 -244.5q0 -185 131.5 -316.5t316.5 -131.5q126 0 232.5 65t165 175.5t49.5 236.5zM1571 249l58 -114l-256 -128 q-13 -7 -29 -7q-40 0 -57 35l-239 477h-472q-24 0 -42.5 16.5t-21.5 40.5l-96 779q-2 17 6 42q14 51 57 82.5t97 31.5q66 0 113 -47t47 -113q0 -69 -52 -117.5t-120 -41.5l37 -289h423v-128h-407l16 -128h455q40 0 57 -35l228 -455z" /> <glyph glyph-name="vimeo_square" unicode="" d="M1292 898q10 216 -161 222q-231 8 -312 -261q44 19 82 19q85 0 74 -96q-4 -57 -74 -167t-105 -110q-43 0 -82 169q-13 54 -45 255q-30 189 -160 177q-59 -7 -164 -100l-81 -72l-81 -72l52 -67q76 52 87 52q57 0 107 -179q15 -55 45 -164.5t45 -164.5q68 -179 164 -179 q157 0 383 294q220 283 226 444zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="_380" unicode="" horiz-adv-x="1152" d="M1152 704q0 -191 -94.5 -353t-256.5 -256.5t-353 -94.5h-160q-14 0 -23 9t-9 23v611l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v93l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v250q0 14 9 23t23 9h160 q14 0 23 -9t9 -23v-181l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-93l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-487q188 13 318 151t130 328q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" /> <glyph glyph-name="plus_square_o" unicode="" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-352v-352q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v352h-352q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h352v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-352h352q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832 q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="_382" unicode="" horiz-adv-x="2176" d="M620 416q-110 -64 -268 -64h-128v64h-64q-13 0 -22.5 23.5t-9.5 56.5q0 24 7 49q-58 2 -96.5 10.5t-38.5 20.5t38.5 20.5t96.5 10.5q-7 25 -7 49q0 33 9.5 56.5t22.5 23.5h64v64h128q158 0 268 -64h1113q42 -7 106.5 -18t80.5 -14q89 -15 150 -40.5t83.5 -47.5t22.5 -40 t-22.5 -40t-83.5 -47.5t-150 -40.5q-16 -3 -80.5 -14t-106.5 -18h-1113zM1739 668q53 -36 53 -92t-53 -92l81 -30q68 48 68 122t-68 122zM625 400h1015q-217 -38 -456 -80q-57 0 -113 -24t-83 -48l-28 -24l-288 -288q-26 -26 -70.5 -45t-89.5 -19h-96l-93 464h29 q157 0 273 64zM352 816h-29l93 464h96q46 0 90 -19t70 -45l288 -288q4 -4 11 -10.5t30.5 -23t48.5 -29t61.5 -23t72.5 -10.5l456 -80h-1015q-116 64 -273 64z" /> <glyph glyph-name="_383" unicode="" horiz-adv-x="1664" d="M1519 760q62 0 103.5 -40.5t41.5 -101.5q0 -97 -93 -130l-172 -59l56 -167q7 -21 7 -47q0 -59 -42 -102t-101 -43q-47 0 -85.5 27t-53.5 72l-55 165l-310 -106l55 -164q8 -24 8 -47q0 -59 -42 -102t-102 -43q-47 0 -85 27t-53 72l-55 163l-153 -53q-29 -9 -50 -9 q-61 0 -101.5 40t-40.5 101q0 47 27.5 85t71.5 53l156 53l-105 313l-156 -54q-26 -8 -48 -8q-60 0 -101 40.5t-41 100.5q0 47 27.5 85t71.5 53l157 53l-53 159q-8 24 -8 47q0 60 42 102.5t102 42.5q47 0 85 -27t53 -72l54 -160l310 105l-54 160q-8 24 -8 47q0 59 42.5 102 t101.5 43q47 0 85.5 -27.5t53.5 -71.5l53 -161l162 55q21 6 43 6q60 0 102.5 -39.5t42.5 -98.5q0 -45 -30 -81.5t-74 -51.5l-157 -54l105 -316l164 56q24 8 46 8zM725 498l310 105l-105 315l-310 -107z" /> <glyph glyph-name="_384" unicode="" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM1280 352v436q-31 -35 -64 -55q-34 -22 -132.5 -85t-151.5 -99q-98 -69 -164 -69v0v0q-66 0 -164 69 q-47 32 -142 92.5t-142 92.5q-12 8 -33 27t-31 27v-436q0 -40 28 -68t68 -28h832q40 0 68 28t28 68zM1280 925q0 41 -27.5 70t-68.5 29h-832q-40 0 -68 -28t-28 -68q0 -37 30.5 -76.5t67.5 -64.5q47 -32 137.5 -89t129.5 -83q3 -2 17 -11.5t21 -14t21 -13t23.5 -13 t21.5 -9.5t22.5 -7.5t20.5 -2.5t20.5 2.5t22.5 7.5t21.5 9.5t23.5 13t21 13t21 14t17 11.5l267 174q35 23 66.5 62.5t31.5 73.5z" /> <glyph glyph-name="_385" unicode="" horiz-adv-x="1792" d="M127 640q0 163 67 313l367 -1005q-196 95 -315 281t-119 411zM1415 679q0 -19 -2.5 -38.5t-10 -49.5t-11.5 -44t-17.5 -59t-17.5 -58l-76 -256l-278 826q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-75 1 -202 10q-12 1 -20.5 -5t-11.5 -15t-1.5 -18.5t9 -16.5 t19.5 -8l80 -8l120 -328l-168 -504l-280 832q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-7 0 -23 0.5t-26 0.5q105 160 274.5 253.5t367.5 93.5q147 0 280.5 -53t238.5 -149h-10q-55 0 -92 -40.5t-37 -95.5q0 -12 2 -24t4 -21.5t8 -23t9 -21t12 -22.5t12.5 -21 t14.5 -24t14 -23q63 -107 63 -212zM909 573l237 -647q1 -6 5 -11q-126 -44 -255 -44q-112 0 -217 32zM1570 1009q95 -174 95 -369q0 -209 -104 -385.5t-279 -278.5l235 678q59 169 59 276q0 42 -6 79zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286 t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 -215q173 0 331.5 68t273 182.5t182.5 273t68 331.5t-68 331.5t-182.5 273t-273 182.5t-331.5 68t-331.5 -68t-273 -182.5t-182.5 -273t-68 -331.5t68 -331.5t182.5 -273 t273 -182.5t331.5 -68z" /> <glyph glyph-name="_386" unicode="" horiz-adv-x="1792" d="M1086 1536v-1536l-272 -128q-228 20 -414 102t-293 208.5t-107 272.5q0 140 100.5 263.5t275 205.5t391.5 108v-172q-217 -38 -356.5 -150t-139.5 -255q0 -152 154.5 -267t388.5 -145v1360zM1755 954l37 -390l-525 114l147 83q-119 70 -280 99v172q277 -33 481 -157z" /> <glyph glyph-name="_387" unicode="" horiz-adv-x="2048" d="M960 1536l960 -384v-128h-128q0 -26 -20.5 -45t-48.5 -19h-1526q-28 0 -48.5 19t-20.5 45h-128v128zM256 896h256v-768h128v768h256v-768h128v768h256v-768h128v768h256v-768h59q28 0 48.5 -19t20.5 -45v-64h-1664v64q0 26 20.5 45t48.5 19h59v768zM1851 -64 q28 0 48.5 -19t20.5 -45v-128h-1920v128q0 26 20.5 45t48.5 19h1782z" /> <glyph glyph-name="_388" unicode="" horiz-adv-x="2304" d="M1774 700l18 -316q4 -69 -82 -128t-235 -93.5t-323 -34.5t-323 34.5t-235 93.5t-82 128l18 316l574 -181q22 -7 48 -7t48 7zM2304 1024q0 -23 -22 -31l-1120 -352q-4 -1 -10 -1t-10 1l-652 206q-43 -34 -71 -111.5t-34 -178.5q63 -36 63 -109q0 -69 -58 -107l58 -433 q2 -14 -8 -25q-9 -11 -24 -11h-192q-15 0 -24 11q-10 11 -8 25l58 433q-58 38 -58 107q0 73 65 111q11 207 98 330l-333 104q-22 8 -22 31t22 31l1120 352q4 1 10 1t10 -1l1120 -352q22 -8 22 -31z" /> <glyph glyph-name="_389" unicode="" d="M859 579l13 -707q-62 11 -105 11q-41 0 -105 -11l13 707q-40 69 -168.5 295.5t-216.5 374.5t-181 287q58 -15 108 -15q44 0 111 15q63 -111 133.5 -229.5t167 -276.5t138.5 -227q37 61 109.5 177.5t117.5 190t105 176t107 189.5q54 -14 107 -14q56 0 114 14v0 q-28 -39 -60 -88.5t-49.5 -78.5t-56.5 -96t-49 -84q-146 -248 -353 -610z" /> <glyph glyph-name="uniF1A0" unicode="" d="M768 750h725q12 -67 12 -128q0 -217 -91 -387.5t-259.5 -266.5t-386.5 -96q-157 0 -299 60.5t-245 163.5t-163.5 245t-60.5 299t60.5 299t163.5 245t245 163.5t299 60.5q300 0 515 -201l-209 -201q-123 119 -306 119q-129 0 -238.5 -65t-173.5 -176.5t-64 -243.5 t64 -243.5t173.5 -176.5t238.5 -65q87 0 160 24t120 60t82 82t51.5 87t22.5 78h-436v264z" /> <glyph glyph-name="f1a1" unicode="" horiz-adv-x="1792" d="M1095 369q16 -16 0 -31q-62 -62 -199 -62t-199 62q-16 15 0 31q6 6 15 6t15 -6q48 -49 169 -49q120 0 169 49q6 6 15 6t15 -6zM788 550q0 -37 -26 -63t-63 -26t-63.5 26t-26.5 63q0 38 26.5 64t63.5 26t63 -26.5t26 -63.5zM1183 550q0 -37 -26.5 -63t-63.5 -26t-63 26 t-26 63t26 63.5t63 26.5t63.5 -26t26.5 -64zM1434 670q0 49 -35 84t-85 35t-86 -36q-130 90 -311 96l63 283l200 -45q0 -37 26 -63t63 -26t63.5 26.5t26.5 63.5t-26.5 63.5t-63.5 26.5q-54 0 -80 -50l-221 49q-19 5 -25 -16l-69 -312q-180 -7 -309 -97q-35 37 -87 37 q-50 0 -85 -35t-35 -84q0 -35 18.5 -64t49.5 -44q-6 -27 -6 -56q0 -142 140 -243t337 -101q198 0 338 101t140 243q0 32 -7 57q30 15 48 43.5t18 63.5zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191 t348 71t348 -71t286 -191t191 -286t71 -348z" /> <glyph glyph-name="_392" unicode="" d="M939 407q13 -13 0 -26q-53 -53 -171 -53t-171 53q-13 13 0 26q5 6 13 6t13 -6q42 -42 145 -42t145 42q5 6 13 6t13 -6zM676 563q0 -31 -23 -54t-54 -23t-54 23t-23 54q0 32 22.5 54.5t54.5 22.5t54.5 -22.5t22.5 -54.5zM1014 563q0 -31 -23 -54t-54 -23t-54 23t-23 54 q0 32 22.5 54.5t54.5 22.5t54.5 -22.5t22.5 -54.5zM1229 666q0 42 -30 72t-73 30q-42 0 -73 -31q-113 78 -267 82l54 243l171 -39q1 -32 23.5 -54t53.5 -22q32 0 54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5q-48 0 -69 -43l-189 42q-17 5 -21 -13l-60 -268q-154 -6 -265 -83 q-30 32 -74 32q-43 0 -73 -30t-30 -72q0 -30 16 -55t42 -38q-5 -25 -5 -48q0 -122 120 -208.5t289 -86.5q170 0 290 86.5t120 208.5q0 25 -6 49q25 13 40.5 37.5t15.5 54.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="_393" unicode="" d="M866 697l90 27v62q0 79 -58 135t-138 56t-138 -55.5t-58 -134.5v-283q0 -20 -14 -33.5t-33 -13.5t-32.5 13.5t-13.5 33.5v120h-151v-122q0 -82 57.5 -139t139.5 -57q81 0 138.5 56.5t57.5 136.5v280q0 19 13.5 33t33.5 14q19 0 32.5 -14t13.5 -33v-54zM1199 502v122h-150 v-126q0 -20 -13.5 -33.5t-33.5 -13.5q-19 0 -32.5 14t-13.5 33v123l-90 -26l-60 28v-123q0 -80 58 -137t139 -57t138.5 57t57.5 139zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103 t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="f1a4" unicode="" horiz-adv-x="1920" d="M1062 824v118q0 42 -30 72t-72 30t-72 -30t-30 -72v-612q0 -175 -126 -299t-303 -124q-178 0 -303.5 125.5t-125.5 303.5v266h328v-262q0 -43 30 -72.5t72 -29.5t72 29.5t30 72.5v620q0 171 126.5 292t301.5 121q176 0 302 -122t126 -294v-136l-195 -58zM1592 602h328 v-266q0 -178 -125.5 -303.5t-303.5 -125.5q-177 0 -303 124.5t-126 300.5v268l131 -61l195 58v-270q0 -42 30 -71.5t72 -29.5t72 29.5t30 71.5v275z" /> <glyph glyph-name="_395" unicode="" d="M1472 160v480h-704v704h-480q-93 0 -158.5 -65.5t-65.5 -158.5v-480h704v-704h480q93 0 158.5 65.5t65.5 158.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" /> <glyph glyph-name="_396" unicode="" horiz-adv-x="2048" d="M328 1254h204v-983h-532v697h328v286zM328 435v369h-123v-369h123zM614 968v-697h205v697h-205zM614 1254v-204h205v204h-205zM901 968h533v-942h-533v163h328v82h-328v697zM1229 435v369h-123v-369h123zM1516 968h532v-942h-532v163h327v82h-327v697zM1843 435v369h-123 v-369h123z" /> <glyph glyph-name="_397" unicode="" d="M1046 516q0 -64 -38 -109t-91 -45q-43 0 -70 15v277q28 17 70 17q53 0 91 -45.5t38 -109.5zM703 944q0 -64 -38 -109.5t-91 -45.5q-43 0 -70 15v277q28 17 70 17q53 0 91 -45t38 -109zM1265 513q0 134 -88 229t-213 95q-20 0 -39 -3q-23 -78 -78 -136q-87 -95 -211 -101 v-636l211 41v206q51 -19 117 -19q125 0 213 95t88 229zM922 940q0 134 -88.5 229t-213.5 95q-74 0 -141 -36h-186v-840l211 41v206q55 -19 116 -19q125 0 213.5 95t88.5 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="_398" unicode="" horiz-adv-x="2038" d="M1222 607q75 3 143.5 -20.5t118 -58.5t101 -94.5t84 -108t75.5 -120.5q33 -56 78.5 -109t75.5 -80.5t99 -88.5q-48 -30 -108.5 -57.5t-138.5 -59t-114 -47.5q-44 37 -74 115t-43.5 164.5t-33 180.5t-42.5 168.5t-72.5 123t-122.5 48.5l-10 -2l-6 -4q4 -5 13 -14 q6 -5 28 -23.5t25.5 -22t19 -18t18 -20.5t11.5 -21t10.5 -27.5t4.5 -31t4 -40.5l1 -33q1 -26 -2.5 -57.5t-7.5 -52t-12.5 -58.5t-11.5 -53q-35 1 -101 -9.5t-98 -10.5q-39 0 -72 10q-2 16 -2 47q0 74 3 96q2 13 31.5 41.5t57 59t26.5 51.5q-24 2 -43 -24 q-36 -53 -111.5 -99.5t-136.5 -46.5q-25 0 -75.5 63t-106.5 139.5t-84 96.5q-6 4 -27 30q-482 -112 -513 -112q-16 0 -28 11t-12 27q0 15 8.5 26.5t22.5 14.5l486 106q-8 14 -8 25t5.5 17.5t16 11.5t20 7t23 4.5t18.5 4.5q4 1 15.5 7.5t17.5 6.5q15 0 28 -16t20 -33 q163 37 172 37q17 0 29.5 -11t12.5 -28q0 -15 -8.5 -26t-23.5 -14l-182 -40l-1 -16q-1 -26 81.5 -117.5t104.5 -91.5q47 0 119 80t72 129q0 36 -23.5 53t-51 18.5t-51 11.5t-23.5 34q0 16 10 34l-68 19q43 44 43 117q0 26 -5 58q82 16 144 16q44 0 71.5 -1.5t48.5 -8.5 t31 -13.5t20.5 -24.5t15.5 -33.5t17 -47.5t24 -60l50 25q-3 -40 -23 -60t-42.5 -21t-40 -6.5t-16.5 -20.5zM1282 842q-5 5 -13.5 15.5t-12 14.5t-10.5 11.5t-10 10.5l-8 8t-8.5 7.5t-8 5t-8.5 4.5q-7 3 -14.5 5t-20.5 2.5t-22 0.5h-32.5h-37.5q-126 0 -217 -43 q16 30 36 46.5t54 29.5t65.5 36t46 36.5t50 55t43.5 50.5q12 -9 28 -31.5t32 -36.5t38 -13l12 1v-76l22 -1q247 95 371 190q28 21 50 39t42.5 37.5t33 31t29.5 34t24 31t24.5 37t23 38t27 47.5t29.5 53l7 9q-2 -53 -43 -139q-79 -165 -205 -264t-306 -142q-14 -3 -42 -7.5 t-50 -9.5t-39 -14q3 -19 24.5 -46t21.5 -34q0 -11 -26 -30zM1061 -79q39 26 131.5 47.5t146.5 21.5q9 0 22.5 -15.5t28 -42.5t26 -50t24 -51t14.5 -33q-121 -45 -244 -45q-61 0 -125 11zM822 568l48 12l109 -177l-73 -48zM1323 51q3 -15 3 -16q0 -7 -17.5 -14.5t-46 -13 t-54 -9.5t-53.5 -7.5t-32 -4.5l-7 43q21 2 60.5 8.5t72 10t60.5 3.5h14zM866 679l-96 -20l-6 17q10 1 32.5 7t34.5 6q19 0 35 -10zM1061 45h31l10 -83l-41 -12v95zM1950 1535v1v-1zM1950 1535l-1 -5l-2 -2l1 3zM1950 1535l1 1z" /> <glyph glyph-name="_399" unicode="" d="M1167 -50q-5 19 -24 5q-30 -22 -87 -39t-131 -17q-129 0 -193 49q-5 4 -13 4q-11 0 -26 -12q-7 -6 -7.5 -16t7.5 -20q34 -32 87.5 -46t102.5 -12.5t99 4.5q41 4 84.5 20.5t65 30t28.5 20.5q12 12 7 29zM1128 65q-19 47 -39 61q-23 15 -76 15q-47 0 -71 -10 q-29 -12 -78 -56q-26 -24 -12 -44q9 -8 17.5 -4.5t31.5 23.5q3 2 10.5 8.5t10.5 8.5t10 7t11.5 7t12.5 5t15 4.5t16.5 2.5t20.5 1q27 0 44.5 -7.5t23 -14.5t13.5 -22q10 -17 12.5 -20t12.5 1q23 12 14 34zM1483 346q0 22 -5 44.5t-16.5 45t-34 36.5t-52.5 14 q-33 0 -97 -41.5t-129 -83.5t-101 -42q-27 -1 -63.5 19t-76 49t-83.5 58t-100 49t-111 19q-115 -1 -197 -78.5t-84 -178.5q-2 -112 74 -164q29 -20 62.5 -28.5t103.5 -8.5q57 0 132 32.5t134 71t120 70.5t93 31q26 -1 65 -31.5t71.5 -67t68 -67.5t55.5 -32q35 -3 58.5 14 t55.5 63q28 41 42.5 101t14.5 106zM1536 506q0 -164 -62 -304.5t-166 -236t-242.5 -149.5t-290.5 -54t-293 57.5t-247.5 157t-170.5 241.5t-64 302q0 89 19.5 172.5t49 145.5t70.5 118.5t78.5 94t78.5 69.5t64.5 46.5t42.5 24.5q14 8 51 26.5t54.5 28.5t48 30t60.5 44 q36 28 58 72.5t30 125.5q129 -155 186 -193q44 -29 130 -68t129 -66q21 -13 39 -25t60.5 -46.5t76 -70.5t75 -95t69 -122t47 -148.5t19.5 -177.5z" /> <glyph glyph-name="_400" unicode="" d="M1070 463l-160 -160l-151 -152l-30 -30q-65 -64 -151.5 -87t-171.5 -2q-16 -70 -72 -115t-129 -45q-85 0 -145 60.5t-60 145.5q0 72 44.5 128t113.5 72q-22 86 1 173t88 152l12 12l151 -152l-11 -11q-37 -37 -37 -89t37 -90q37 -37 89 -37t89 37l30 30l151 152l161 160z M729 1145l12 -12l-152 -152l-12 12q-37 37 -89 37t-89 -37t-37 -89.5t37 -89.5l29 -29l152 -152l160 -160l-151 -152l-161 160l-151 152l-30 30q-68 67 -90 159.5t5 179.5q-70 15 -115 71t-45 129q0 85 60 145.5t145 60.5q76 0 133.5 -49t69.5 -123q84 20 169.5 -3.5 t149.5 -87.5zM1536 78q0 -85 -60 -145.5t-145 -60.5q-74 0 -131 47t-71 118q-86 -28 -179.5 -6t-161.5 90l-11 12l151 152l12 -12q37 -37 89 -37t89 37t37 89t-37 89l-30 30l-152 152l-160 160l152 152l160 -160l152 -152l29 -30q64 -64 87.5 -150.5t2.5 -171.5 q76 -11 126.5 -68.5t50.5 -134.5zM1534 1202q0 -77 -51 -135t-127 -69q26 -85 3 -176.5t-90 -158.5l-12 -12l-151 152l12 12q37 37 37 89t-37 89t-89 37t-89 -37l-30 -30l-152 -152l-160 -160l-152 152l161 160l152 152l29 30q67 67 159 89.5t178 -3.5q11 75 68.5 126 t135.5 51q85 0 145 -60.5t60 -145.5z" /> <glyph glyph-name="f1ab" unicode="" d="M654 458q-1 -3 -12.5 0.5t-31.5 11.5l-20 9q-44 20 -87 49q-7 5 -41 31.5t-38 28.5q-67 -103 -134 -181q-81 -95 -105 -110q-4 -2 -19.5 -4t-18.5 0q6 4 82 92q21 24 85.5 115t78.5 118q17 30 51 98.5t36 77.5q-8 1 -110 -33q-8 -2 -27.5 -7.5t-34.5 -9.5t-17 -5 q-2 -2 -2 -10.5t-1 -9.5q-5 -10 -31 -15q-23 -7 -47 0q-18 4 -28 21q-4 6 -5 23q6 2 24.5 5t29.5 6q58 16 105 32q100 35 102 35q10 2 43 19.5t44 21.5q9 3 21.5 8t14.5 5.5t6 -0.5q2 -12 -1 -33q0 -2 -12.5 -27t-26.5 -53.5t-17 -33.5q-25 -50 -77 -131l64 -28 q12 -6 74.5 -32t67.5 -28q4 -1 10.5 -25.5t4.5 -30.5zM449 944q3 -15 -4 -28q-12 -23 -50 -38q-30 -12 -60 -12q-26 3 -49 26q-14 15 -18 41l1 3q3 -3 19.5 -5t26.5 0t58 16q36 12 55 14q17 0 21 -17zM1147 815l63 -227l-139 42zM39 15l694 232v1032l-694 -233v-1031z M1280 332l102 -31l-181 657l-100 31l-216 -536l102 -31l45 110l211 -65zM777 1294l573 -184v380zM1088 -29l158 -13l-54 -160l-40 66q-130 -83 -276 -108q-58 -12 -91 -12h-84q-79 0 -199.5 39t-183.5 85q-8 7 -8 16q0 8 5 13.5t13 5.5q4 0 18 -7.5t30.5 -16.5t20.5 -11 q73 -37 159.5 -61.5t157.5 -24.5q95 0 167 14.5t157 50.5q15 7 30.5 15.5t34 19t28.5 16.5zM1536 1050v-1079l-774 246q-14 -6 -375 -127.5t-368 -121.5q-13 0 -18 13q0 1 -1 3v1078q3 9 4 10q5 6 20 11q107 36 149 50v384l558 -198q2 0 160.5 55t316 108.5t161.5 53.5 q20 0 20 -21v-418z" /> <glyph glyph-name="_402" unicode="" horiz-adv-x="1792" d="M288 1152q66 0 113 -47t47 -113v-1088q0 -66 -47 -113t-113 -47h-128q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h128zM1664 989q58 -34 93 -93t35 -128v-768q0 -106 -75 -181t-181 -75h-864q-66 0 -113 47t-47 113v1536q0 40 28 68t68 28h672q40 0 88 -20t76 -48 l152 -152q28 -28 48 -76t20 -88v-163zM928 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 512v128q0 14 -9 23 t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128 q14 0 23 9t9 23zM1184 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 256v128q0 14 -9 23t-23 9h-128 q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1536 896v256h-160q-40 0 -68 28t-28 68v160h-640v-512h896z" /> <glyph glyph-name="_403" unicode="" d="M1344 1536q26 0 45 -19t19 -45v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280zM512 1248v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 992v-64q0 -14 9 -23t23 -9h64q14 0 23 9 t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 736v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 480v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 160v64 q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 q14 0 23 9t9 23zM384 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 -96v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9 t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM896 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 928v64 q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 160v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9 t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23z" /> <glyph glyph-name="_404" unicode="" horiz-adv-x="1280" d="M1188 988l-292 -292v-824q0 -46 -33 -79t-79 -33t-79 33t-33 79v384h-64v-384q0 -46 -33 -79t-79 -33t-79 33t-33 79v824l-292 292q-28 28 -28 68t28 68q29 28 68.5 28t67.5 -28l228 -228h368l228 228q28 28 68 28t68 -28q28 -29 28 -68.5t-28 -67.5zM864 1152 q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" /> <glyph glyph-name="uniF1B1" unicode="" horiz-adv-x="1664" d="M780 1064q0 -60 -19 -113.5t-63 -92.5t-105 -39q-76 0 -138 57.5t-92 135.5t-30 151q0 60 19 113.5t63 92.5t105 39q77 0 138.5 -57.5t91.5 -135t30 -151.5zM438 581q0 -80 -42 -139t-119 -59q-76 0 -141.5 55.5t-100.5 133.5t-35 152q0 80 42 139.5t119 59.5 q76 0 141.5 -55.5t100.5 -134t35 -152.5zM832 608q118 0 255 -97.5t229 -237t92 -254.5q0 -46 -17 -76.5t-48.5 -45t-64.5 -20t-76 -5.5q-68 0 -187.5 45t-182.5 45q-66 0 -192.5 -44.5t-200.5 -44.5q-183 0 -183 146q0 86 56 191.5t139.5 192.5t187.5 146t193 59zM1071 819 q-61 0 -105 39t-63 92.5t-19 113.5q0 74 30 151.5t91.5 135t138.5 57.5q61 0 105 -39t63 -92.5t19 -113.5q0 -73 -30 -151t-92 -135.5t-138 -57.5zM1503 923q77 0 119 -59.5t42 -139.5q0 -74 -35 -152t-100.5 -133.5t-141.5 -55.5q-77 0 -119 59t-42 139q0 74 35 152.5 t100.5 134t141.5 55.5z" /> <glyph glyph-name="_406" unicode="" horiz-adv-x="768" d="M704 1008q0 -145 -57 -243.5t-152 -135.5l45 -821q2 -26 -16 -45t-44 -19h-192q-26 0 -44 19t-16 45l45 821q-95 37 -152 135.5t-57 243.5q0 128 42.5 249.5t117.5 200t160 78.5t160 -78.5t117.5 -200t42.5 -249.5z" /> <glyph glyph-name="_407" unicode="" horiz-adv-x="1792" d="M896 -93l640 349v636l-640 -233v-752zM832 772l698 254l-698 254l-698 -254zM1664 1024v-768q0 -35 -18 -65t-49 -47l-704 -384q-28 -16 -61 -16t-61 16l-704 384q-31 17 -49 47t-18 65v768q0 40 23 73t61 47l704 256q22 8 44 8t44 -8l704 -256q38 -14 61 -47t23 -73z " /> <glyph glyph-name="_408" unicode="" horiz-adv-x="2304" d="M640 -96l384 192v314l-384 -164v-342zM576 358l404 173l-404 173l-404 -173zM1664 -96l384 192v314l-384 -164v-342zM1600 358l404 173l-404 173l-404 -173zM1152 651l384 165v266l-384 -164v-267zM1088 1030l441 189l-441 189l-441 -189zM2176 512v-416q0 -36 -19 -67 t-52 -47l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-4 2 -7 4q-2 -2 -7 -4l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-33 16 -52 47t-19 67v416q0 38 21.5 70t56.5 48l434 186v400q0 38 21.5 70t56.5 48l448 192q23 10 50 10t50 -10l448 -192q35 -16 56.5 -48t21.5 -70 v-400l434 -186q36 -16 57 -48t21 -70z" /> <glyph glyph-name="_409" unicode="" horiz-adv-x="2048" d="M1848 1197h-511v-124h511v124zM1596 771q-90 0 -146 -52.5t-62 -142.5h408q-18 195 -200 195zM1612 186q63 0 122 32t76 87h221q-100 -307 -427 -307q-214 0 -340.5 132t-126.5 347q0 208 130.5 345.5t336.5 137.5q138 0 240.5 -68t153 -179t50.5 -248q0 -17 -2 -47h-658 q0 -111 57.5 -171.5t166.5 -60.5zM277 236h296q205 0 205 167q0 180 -199 180h-302v-347zM277 773h281q78 0 123.5 36.5t45.5 113.5q0 144 -190 144h-260v-294zM0 1282h594q87 0 155 -14t126.5 -47.5t90 -96.5t31.5 -154q0 -181 -172 -263q114 -32 172 -115t58 -204 q0 -75 -24.5 -136.5t-66 -103.5t-98.5 -71t-121 -42t-134 -13h-611v1260z" /> <glyph glyph-name="_410" unicode="" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM499 1041h-371v-787h382q117 0 197 57.5t80 170.5q0 158 -143 200q107 52 107 164q0 57 -19.5 96.5 t-56.5 60.5t-79 29.5t-97 8.5zM477 723h-176v184h163q119 0 119 -90q0 -94 -106 -94zM486 388h-185v217h189q124 0 124 -113q0 -104 -128 -104zM1136 356q-68 0 -104 38t-36 107h411q1 10 1 30q0 132 -74.5 220.5t-203.5 88.5q-128 0 -210 -86t-82 -216q0 -135 79 -217 t213 -82q205 0 267 191h-138q-11 -34 -47.5 -54t-75.5 -20zM1126 722q113 0 124 -122h-254q4 56 39 89t91 33zM964 988h319v-77h-319v77z" /> <glyph glyph-name="_411" unicode="" horiz-adv-x="1792" d="M1582 954q0 -101 -71.5 -172.5t-172.5 -71.5t-172.5 71.5t-71.5 172.5t71.5 172.5t172.5 71.5t172.5 -71.5t71.5 -172.5zM812 212q0 104 -73 177t-177 73q-27 0 -54 -6l104 -42q77 -31 109.5 -106.5t1.5 -151.5q-31 -77 -107 -109t-152 -1q-21 8 -62 24.5t-61 24.5 q32 -60 91 -96.5t130 -36.5q104 0 177 73t73 177zM1642 953q0 126 -89.5 215.5t-215.5 89.5q-127 0 -216.5 -89.5t-89.5 -215.5q0 -127 89.5 -216t216.5 -89q126 0 215.5 89t89.5 216zM1792 953q0 -189 -133.5 -322t-321.5 -133l-437 -319q-12 -129 -109 -218t-229 -89 q-121 0 -214 76t-118 192l-230 92v429l389 -157q79 48 173 48q13 0 35 -2l284 407q2 187 135.5 319t320.5 132q188 0 321.5 -133.5t133.5 -321.5z" /> <glyph glyph-name="_412" unicode="" d="M1242 889q0 80 -57 136.5t-137 56.5t-136.5 -57t-56.5 -136q0 -80 56.5 -136.5t136.5 -56.5t137 56.5t57 136.5zM632 301q0 -83 -58 -140.5t-140 -57.5q-56 0 -103 29t-72 77q52 -20 98 -40q60 -24 120 1.5t85 86.5q24 60 -1.5 120t-86.5 84l-82 33q22 5 42 5 q82 0 140 -57.5t58 -140.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v153l172 -69q20 -92 93.5 -152t168.5 -60q104 0 181 70t87 173l345 252q150 0 255.5 105.5t105.5 254.5q0 150 -105.5 255.5t-255.5 105.5 q-148 0 -253 -104.5t-107 -252.5l-225 -322q-9 1 -28 1q-75 0 -137 -37l-297 119v468q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5zM1289 887q0 -100 -71 -170.5t-171 -70.5t-170.5 70.5t-70.5 170.5t70.5 171t170.5 71q101 0 171.5 -70.5t70.5 -171.5z " /> <glyph glyph-name="_413" unicode="" horiz-adv-x="1792" d="M836 367l-15 -368l-2 -22l-420 29q-36 3 -67 31.5t-47 65.5q-11 27 -14.5 55t4 65t12 55t21.5 64t19 53q78 -12 509 -28zM449 953l180 -379l-147 92q-63 -72 -111.5 -144.5t-72.5 -125t-39.5 -94.5t-18.5 -63l-4 -21l-190 357q-17 26 -18 56t6 47l8 18q35 63 114 188 l-140 86zM1680 436l-188 -359q-12 -29 -36.5 -46.5t-43.5 -20.5l-18 -4q-71 -7 -219 -12l8 -164l-230 367l211 362l7 -173q170 -16 283 -5t170 33zM895 1360q-47 -63 -265 -435l-317 187l-19 12l225 356q20 31 60 45t80 10q24 -2 48.5 -12t42 -21t41.5 -33t36 -34.5 t36 -39.5t32 -35zM1550 1053l212 -363q18 -37 12.5 -76t-27.5 -74q-13 -20 -33 -37t-38 -28t-48.5 -22t-47 -16t-51.5 -14t-46 -12q-34 72 -265 436l313 195zM1407 1279l142 83l-220 -373l-419 20l151 86q-34 89 -75 166t-75.5 123.5t-64.5 80t-47 46.5l-17 13l405 -1 q31 3 58 -10.5t39 -28.5l11 -15q39 -61 112 -190z" /> <glyph glyph-name="_414" unicode="" horiz-adv-x="2048" d="M480 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM516 768h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5zM1888 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM2048 544v-384 q0 -14 -9 -23t-23 -9h-96v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-1024v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5t179 63.5h768q98 0 179 -63.5t104 -157.5 l105 -419h28q93 0 158.5 -65.5t65.5 -158.5z" /> <glyph glyph-name="_415" unicode="" horiz-adv-x="2048" d="M1824 640q93 0 158.5 -65.5t65.5 -158.5v-384q0 -14 -9 -23t-23 -9h-96v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-1024v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5 t179 63.5h128v224q0 14 9 23t23 9h448q14 0 23 -9t9 -23v-224h128q98 0 179 -63.5t104 -157.5l105 -419h28zM320 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM516 640h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5z M1728 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47z" /> <glyph glyph-name="_416" unicode="" d="M1504 64q0 -26 -19 -45t-45 -19h-462q1 -17 6 -87.5t5 -108.5q0 -25 -18 -42.5t-43 -17.5h-320q-25 0 -43 17.5t-18 42.5q0 38 5 108.5t6 87.5h-462q-26 0 -45 19t-19 45t19 45l402 403h-229q-26 0 -45 19t-19 45t19 45l402 403h-197q-26 0 -45 19t-19 45t19 45l384 384 q19 19 45 19t45 -19l384 -384q19 -19 19 -45t-19 -45t-45 -19h-197l402 -403q19 -19 19 -45t-19 -45t-45 -19h-229l402 -403q19 -19 19 -45z" /> <glyph glyph-name="_417" unicode="" d="M1127 326q0 32 -30 51q-193 115 -447 115q-133 0 -287 -34q-42 -9 -42 -52q0 -20 13.5 -34.5t35.5 -14.5q5 0 37 8q132 27 243 27q226 0 397 -103q19 -11 33 -11q19 0 33 13.5t14 34.5zM1223 541q0 40 -35 61q-237 141 -548 141q-153 0 -303 -42q-48 -13 -48 -64 q0 -25 17.5 -42.5t42.5 -17.5q7 0 37 8q122 33 251 33q279 0 488 -124q24 -13 38 -13q25 0 42.5 17.5t17.5 42.5zM1331 789q0 47 -40 70q-126 73 -293 110.5t-343 37.5q-204 0 -364 -47q-23 -7 -38.5 -25.5t-15.5 -48.5q0 -31 20.5 -52t51.5 -21q11 0 40 8q133 37 307 37 q159 0 309.5 -34t253.5 -95q21 -12 40 -12q29 0 50.5 20.5t21.5 51.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="_418" unicode="" horiz-adv-x="1024" d="M1024 1233l-303 -582l24 -31h279v-415h-507l-44 -30l-142 -273l-30 -30h-301v303l303 583l-24 30h-279v415h507l44 30l142 273l30 30h301v-303z" /> <glyph glyph-name="_419" unicode="" horiz-adv-x="2304" d="M784 164l16 241l-16 523q-1 10 -7.5 17t-16.5 7q-9 0 -16 -7t-7 -17l-14 -523l14 -241q1 -10 7.5 -16.5t15.5 -6.5q22 0 24 23zM1080 193l11 211l-12 586q0 16 -13 24q-8 5 -16 5t-16 -5q-13 -8 -13 -24l-1 -6l-10 -579q0 -1 11 -236v-1q0 -10 6 -17q9 -11 23 -11 q11 0 20 9q9 7 9 20zM35 533l20 -128l-20 -126q-2 -9 -9 -9t-9 9l-17 126l17 128q2 9 9 9t9 -9zM121 612l26 -207l-26 -203q-2 -9 -10 -9q-9 0 -9 10l-23 202l23 207q0 9 9 9q8 0 10 -9zM401 159zM213 650l25 -245l-25 -237q0 -11 -11 -11q-10 0 -12 11l-21 237l21 245 q2 12 12 12q11 0 11 -12zM307 657l23 -252l-23 -244q-2 -13 -14 -13q-13 0 -13 13l-21 244l21 252q0 13 13 13q12 0 14 -13zM401 639l21 -234l-21 -246q-2 -16 -16 -16q-6 0 -10.5 4.5t-4.5 11.5l-20 246l20 234q0 6 4.5 10.5t10.5 4.5q14 0 16 -15zM784 164zM495 785 l21 -380l-21 -246q0 -7 -5 -12.5t-12 -5.5q-16 0 -18 18l-18 246l18 380q2 18 18 18q7 0 12 -5.5t5 -12.5zM589 871l19 -468l-19 -244q0 -8 -5.5 -13.5t-13.5 -5.5q-18 0 -20 19l-16 244l16 468q2 19 20 19q8 0 13.5 -5.5t5.5 -13.5zM687 911l18 -506l-18 -242 q-2 -21 -22 -21q-19 0 -21 21l-16 242l16 506q0 9 6.5 15.5t14.5 6.5q9 0 15 -6.5t7 -15.5zM1079 169v0v0v0zM881 915l15 -510l-15 -239q0 -10 -7.5 -17.5t-17.5 -7.5t-17 7t-8 18l-14 239l14 510q0 11 7.5 18t17.5 7t17.5 -7t7.5 -18zM980 896l14 -492l-14 -236 q0 -11 -8 -19t-19 -8t-19 8t-9 19l-12 236l12 492q1 12 9 20t19 8t18.5 -8t8.5 -20zM1192 404l-14 -231v0q0 -13 -9 -22t-22 -9t-22 9t-10 22l-6 114l-6 117l12 636v3q2 15 12 24q9 7 20 7q8 0 15 -5q14 -8 16 -26zM2304 423q0 -117 -83 -199.5t-200 -82.5h-786 q-13 2 -22 11t-9 22v899q0 23 28 33q85 34 181 34q195 0 338 -131.5t160 -323.5q53 22 110 22q117 0 200 -83t83 -201z" /> <glyph glyph-name="uniF1C0" unicode="" d="M768 768q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 0q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127 t443 -43zM768 384q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 1536q208 0 385 -34.5t280 -93.5t103 -128v-128q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5 t-103 128v128q0 69 103 128t280 93.5t385 34.5z" /> <glyph glyph-name="uniF1C1" unicode="" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M894 465q33 -26 84 -56q59 7 117 7q147 0 177 -49q16 -22 2 -52q0 -1 -1 -2l-2 -2v-1q-6 -38 -71 -38q-48 0 -115 20t-130 53q-221 -24 -392 -83q-153 -262 -242 -262q-15 0 -28 7l-24 12q-1 1 -6 5q-10 10 -6 36q9 40 56 91.5t132 96.5q14 9 23 -6q2 -2 2 -4q52 85 107 197 q68 136 104 262q-24 82 -30.5 159.5t6.5 127.5q11 40 42 40h21h1q23 0 35 -15q18 -21 9 -68q-2 -6 -4 -8q1 -3 1 -8v-30q-2 -123 -14 -192q55 -164 146 -238zM318 54q52 24 137 158q-51 -40 -87.5 -84t-49.5 -74zM716 974q-15 -42 -2 -132q1 7 7 44q0 3 7 43q1 4 4 8 q-1 1 -1 2q-1 2 -1 3q-1 22 -13 36q0 -1 -1 -2v-2zM592 313q135 54 284 81q-2 1 -13 9.5t-16 13.5q-76 67 -127 176q-27 -86 -83 -197q-30 -56 -45 -83zM1238 329q-24 24 -140 24q76 -28 124 -28q14 0 18 1q0 1 -2 3z" /> <glyph glyph-name="_422" unicode="" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M233 768v-107h70l164 -661h159l128 485q7 20 10 46q2 16 2 24h4l3 -24q1 -3 3.5 -20t5.5 -26l128 -485h159l164 661h70v107h-300v-107h90l-99 -438q-5 -20 -7 -46l-2 -21h-4q0 3 -0.5 6.5t-1.5 8t-1 6.5q-1 5 -4 21t-5 25l-144 545h-114l-144 -545q-2 -9 -4.5 -24.5 t-3.5 -21.5l-4 -21h-4l-2 21q-2 26 -7 46l-99 438h90v107h-300z" /> <glyph glyph-name="_423" unicode="" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M429 106v-106h281v106h-75l103 161q5 7 10 16.5t7.5 13.5t3.5 4h2q1 -4 5 -10q2 -4 4.5 -7.5t6 -8t6.5 -8.5l107 -161h-76v-106h291v106h-68l-192 273l195 282h67v107h-279v-107h74l-103 -159q-4 -7 -10 -16.5t-9 -13.5l-2 -3h-2q-1 4 -5 10q-6 11 -17 23l-106 159h76v107 h-290v-107h68l189 -272l-194 -283h-68z" /> <glyph glyph-name="_424" unicode="" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M416 106v-106h327v106h-93v167h137q76 0 118 15q67 23 106.5 87t39.5 146q0 81 -37 141t-100 87q-48 19 -130 19h-368v-107h92v-555h-92zM769 386h-119v268h120q52 0 83 -18q56 -33 56 -115q0 -89 -62 -120q-31 -15 -78 -15z" /> <glyph glyph-name="_425" unicode="" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M1280 320v-320h-1024v192l192 192l128 -128l384 384zM448 512q-80 0 -136 56t-56 136t56 136t136 56t136 -56t56 -136t-56 -136t-136 -56z" /> <glyph glyph-name="_426" unicode="" d="M640 1152v128h-128v-128h128zM768 1024v128h-128v-128h128zM640 896v128h-128v-128h128zM768 768v128h-128v-128h128zM1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400 v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-128v-128h-128v128h-512v-1536h1280zM781 593l107 -349q8 -27 8 -52q0 -83 -72.5 -137.5t-183.5 -54.5t-183.5 54.5t-72.5 137.5q0 25 8 52q21 63 120 396v128h128v-128h79 q22 0 39 -13t23 -34zM640 128q53 0 90.5 19t37.5 45t-37.5 45t-90.5 19t-90.5 -19t-37.5 -45t37.5 -45t90.5 -19z" /> <glyph glyph-name="_427" unicode="" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M620 686q20 -8 20 -30v-544q0 -22 -20 -30q-8 -2 -12 -2q-12 0 -23 9l-166 167h-131q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h131l166 167q16 15 35 7zM1037 -3q31 0 50 24q129 159 129 363t-129 363q-16 21 -43 24t-47 -14q-21 -17 -23.5 -43.5t14.5 -47.5 q100 -123 100 -282t-100 -282q-17 -21 -14.5 -47.5t23.5 -42.5q18 -15 40 -15zM826 145q27 0 47 20q87 93 87 219t-87 219q-18 19 -45 20t-46 -17t-20 -44.5t18 -46.5q52 -57 52 -131t-52 -131q-19 -20 -18 -46.5t20 -44.5q20 -17 44 -17z" /> <glyph glyph-name="_428" unicode="" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M768 768q52 0 90 -38t38 -90v-384q0 -52 -38 -90t-90 -38h-384q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h384zM1260 766q20 -8 20 -30v-576q0 -22 -20 -30q-8 -2 -12 -2q-14 0 -23 9l-265 266v90l265 266q9 9 23 9q4 0 12 -2z" /> <glyph glyph-name="_429" unicode="" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M480 768q8 11 21 12.5t24 -6.5l51 -38q11 -8 12.5 -21t-6.5 -24l-182 -243l182 -243q8 -11 6.5 -24t-12.5 -21l-51 -38q-11 -8 -24 -6.5t-21 12.5l-226 301q-14 19 0 38zM1282 467q14 -19 0 -38l-226 -301q-8 -11 -21 -12.5t-24 6.5l-51 38q-11 8 -12.5 21t6.5 24l182 243 l-182 243q-8 11 -6.5 24t12.5 21l51 38q11 8 24 6.5t21 -12.5zM662 6q-13 2 -20.5 13t-5.5 24l138 831q2 13 13 20.5t24 5.5l63 -10q13 -2 20.5 -13t5.5 -24l-138 -831q-2 -13 -13 -20.5t-24 -5.5z" /> <glyph glyph-name="_430" unicode="" d="M1497 709v-198q-101 -23 -198 -23q-65 -136 -165.5 -271t-181.5 -215.5t-128 -106.5q-80 -45 -162 3q-28 17 -60.5 43.5t-85 83.5t-102.5 128.5t-107.5 184t-105.5 244t-91.5 314.5t-70.5 390h283q26 -218 70 -398.5t104.5 -317t121.5 -235.5t140 -195q169 169 287 406 q-142 72 -223 220t-81 333q0 192 104 314.5t284 122.5q178 0 273 -105.5t95 -297.5q0 -159 -58 -286q-7 -1 -19.5 -3t-46 -2t-63 6t-62 25.5t-50.5 51.5q31 103 31 184q0 87 -29 132t-79 45q-53 0 -85 -49.5t-32 -140.5q0 -186 105 -293.5t267 -107.5q62 0 121 14z" /> <glyph glyph-name="_431" unicode="" horiz-adv-x="1792" d="M216 367l603 -402v359l-334 223zM154 511l193 129l-193 129v-258zM973 -35l603 402l-269 180l-334 -223v-359zM896 458l272 182l-272 182l-272 -182zM485 733l334 223v359l-603 -402zM1445 640l193 -129v258zM1307 733l269 180l-603 402v-359zM1792 913v-546 q0 -41 -34 -64l-819 -546q-21 -13 -43 -13t-43 13l-819 546q-34 23 -34 64v546q0 41 34 64l819 546q21 13 43 13t43 -13l819 -546q34 -23 34 -64z" /> <glyph glyph-name="_432" unicode="" horiz-adv-x="2048" d="M1800 764q111 -46 179.5 -145.5t68.5 -221.5q0 -164 -118 -280.5t-285 -116.5q-4 0 -11.5 0.5t-10.5 0.5h-1209h-1h-2h-5q-170 10 -288 125.5t-118 280.5q0 110 55 203t147 147q-12 39 -12 82q0 115 82 196t199 81q95 0 172 -58q75 154 222.5 248t326.5 94 q166 0 306 -80.5t221.5 -218.5t81.5 -301q0 -6 -0.5 -18t-0.5 -18zM468 498q0 -122 84 -193t208 -71q137 0 240 99q-16 20 -47.5 56.5t-43.5 50.5q-67 -65 -144 -65q-55 0 -93.5 33.5t-38.5 87.5q0 53 38.5 87t91.5 34q44 0 84.5 -21t73 -55t65 -75t69 -82t77 -75t97 -55 t121.5 -21q121 0 204.5 71.5t83.5 190.5q0 121 -84 192t-207 71q-143 0 -241 -97l93 -108q66 64 142 64q52 0 92 -33t40 -84q0 -57 -37 -91.5t-94 -34.5q-43 0 -82.5 21t-72 55t-65.5 75t-69.5 82t-77.5 75t-96.5 55t-118.5 21q-122 0 -207 -70.5t-85 -189.5z" /> <glyph glyph-name="_433" unicode="" horiz-adv-x="1792" d="M896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 1408q-190 0 -361 -90l194 -194q82 28 167 28t167 -28l194 194q-171 90 -361 90zM218 279l194 194 q-28 82 -28 167t28 167l-194 194q-90 -171 -90 -361t90 -361zM896 -128q190 0 361 90l-194 194q-82 -28 -167 -28t-167 28l-194 -194q171 -90 361 -90zM896 256q159 0 271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5 t271.5 -112.5zM1380 473l194 -194q90 171 90 361t-90 361l-194 -194q28 -82 28 -167t-28 -167z" /> <glyph glyph-name="_434" unicode="" horiz-adv-x="1792" d="M1760 640q0 -176 -68.5 -336t-184 -275.5t-275.5 -184t-336 -68.5t-336 68.5t-275.5 184t-184 275.5t-68.5 336q0 213 97 398.5t265 305.5t374 151v-228q-221 -45 -366.5 -221t-145.5 -406q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5 t136.5 204t51 248.5q0 230 -145.5 406t-366.5 221v228q206 -31 374 -151t265 -305.5t97 -398.5z" /> <glyph glyph-name="uniF1D0" unicode="" horiz-adv-x="1792" d="M19 662q8 217 116 406t305 318h5q0 -1 -1 -3q-8 -8 -28 -33.5t-52 -76.5t-60 -110.5t-44.5 -135.5t-14 -150.5t39 -157.5t108.5 -154q50 -50 102 -69.5t90.5 -11.5t69.5 23.5t47 32.5l16 16q39 51 53 116.5t6.5 122.5t-21 107t-26.5 80l-14 29q-10 25 -30.5 49.5t-43 41 t-43.5 29.5t-35 19l-13 6l104 115q39 -17 78 -52t59 -61l19 -27q1 48 -18.5 103.5t-40.5 87.5l-20 31l161 183l160 -181q-33 -46 -52.5 -102.5t-22.5 -90.5l-4 -33q22 37 61.5 72.5t67.5 52.5l28 17l103 -115q-44 -14 -85 -50t-60 -65l-19 -29q-31 -56 -48 -133.5t-7 -170 t57 -156.5q33 -45 77.5 -60.5t85 -5.5t76 26.5t57.5 33.5l21 16q60 53 96.5 115t48.5 121.5t10 121.5t-18 118t-37 107.5t-45.5 93t-45 72t-34.5 47.5l-13 17q-14 13 -7 13l10 -3q40 -29 62.5 -46t62 -50t64 -58t58.5 -65t55.5 -77t45.5 -88t38 -103t23.5 -117t10.5 -136 q3 -259 -108 -465t-312 -321t-456 -115q-185 0 -351 74t-283.5 198t-184 293t-60.5 353z" /> <glyph glyph-name="uniF1D1" unicode="" horiz-adv-x="1792" d="M874 -102v-66q-208 6 -385 109.5t-283 275.5l58 34q29 -49 73 -99l65 57q148 -168 368 -212l-17 -86q65 -12 121 -13zM276 428l-83 -28q22 -60 49 -112l-57 -33q-98 180 -98 385t98 385l57 -33q-30 -56 -49 -112l82 -28q-35 -100 -35 -212q0 -109 36 -212zM1528 251 l58 -34q-106 -172 -283 -275.5t-385 -109.5v66q56 1 121 13l-17 86q220 44 368 212l65 -57q44 50 73 99zM1377 805l-233 -80q14 -42 14 -85t-14 -85l232 -80q-31 -92 -98 -169l-185 162q-57 -67 -147 -85l48 -241q-52 -10 -98 -10t-98 10l48 241q-90 18 -147 85l-185 -162 q-67 77 -98 169l232 80q-14 42 -14 85t14 85l-233 80q33 93 99 169l185 -162q59 68 147 86l-48 240q44 10 98 10t98 -10l-48 -240q88 -18 147 -86l185 162q66 -76 99 -169zM874 1448v-66q-65 -2 -121 -13l17 -86q-220 -42 -368 -211l-65 56q-38 -42 -73 -98l-57 33 q106 172 282 275.5t385 109.5zM1705 640q0 -205 -98 -385l-57 33q27 52 49 112l-83 28q36 103 36 212q0 112 -35 212l82 28q-19 56 -49 112l57 33q98 -180 98 -385zM1585 1063l-57 -33q-35 56 -73 98l-65 -56q-148 169 -368 211l17 86q-56 11 -121 13v66q209 -6 385 -109.5 t282 -275.5zM1748 640q0 173 -67.5 331t-181.5 272t-272 181.5t-331 67.5t-331 -67.5t-272 -181.5t-181.5 -272t-67.5 -331t67.5 -331t181.5 -272t272 -181.5t331 -67.5t331 67.5t272 181.5t181.5 272t67.5 331zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71 t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> <glyph glyph-name="uniF1D2" unicode="" d="M582 228q0 -66 -93 -66q-107 0 -107 63q0 64 98 64q102 0 102 -61zM546 694q0 -85 -74 -85q-77 0 -77 84q0 90 77 90q36 0 55 -25.5t19 -63.5zM712 769v125q-78 -29 -135 -29q-50 29 -110 29q-86 0 -145 -57t-59 -143q0 -50 29.5 -102t73.5 -67v-3q-38 -17 -38 -85 q0 -53 41 -77v-3q-113 -37 -113 -139q0 -45 20 -78.5t54 -51t72 -25.5t81 -8q224 0 224 188q0 67 -48 99t-126 46q-27 5 -51.5 20.5t-24.5 39.5q0 44 49 52q77 15 122 70t45 134q0 24 -10 52q37 9 49 13zM771 350h137q-2 27 -2 82v387q0 46 2 69h-137q3 -23 3 -71v-392 q0 -50 -3 -75zM1280 366v121q-30 -21 -68 -21q-53 0 -53 82v225h52q9 0 26.5 -1t26.5 -1v117h-105q0 82 3 102h-140q4 -24 4 -55v-47h-60v-117q36 3 37 3q3 0 11 -0.5t12 -0.5v-2h-2v-217q0 -37 2.5 -64t11.5 -56.5t24.5 -48.5t43.5 -31t66 -12q64 0 108 24zM924 1072 q0 36 -24 63.5t-60 27.5t-60.5 -27t-24.5 -64q0 -36 25 -62.5t60 -26.5t59.5 27t24.5 62zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="_438" unicode="" horiz-adv-x="1792" d="M595 22q0 100 -165 100q-158 0 -158 -104q0 -101 172 -101q151 0 151 105zM536 777q0 61 -30 102t-89 41q-124 0 -124 -145q0 -135 124 -135q119 0 119 137zM805 1101v-202q-36 -12 -79 -22q16 -43 16 -84q0 -127 -73 -216.5t-197 -112.5q-40 -8 -59.5 -27t-19.5 -58 q0 -31 22.5 -51.5t58 -32t78.5 -22t86 -25.5t78.5 -37.5t58 -64t22.5 -98.5q0 -304 -363 -304q-69 0 -130 12.5t-116 41t-87.5 82t-32.5 127.5q0 165 182 225v4q-67 41 -67 126q0 109 63 137v4q-72 24 -119.5 108.5t-47.5 165.5q0 139 95 231.5t235 92.5q96 0 178 -47 q98 0 218 47zM1123 220h-222q4 45 4 134v609q0 94 -4 128h222q-4 -33 -4 -124v-613q0 -89 4 -134zM1724 442v-196q-71 -39 -174 -39q-62 0 -107 20t-70 50t-39.5 78t-18.5 92t-4 103v351h2v4q-7 0 -19 1t-18 1q-21 0 -59 -6v190h96v76q0 54 -6 89h227q-6 -41 -6 -165h171 v-190q-15 0 -43.5 2t-42.5 2h-85v-365q0 -131 87 -131q61 0 109 33zM1148 1389q0 -58 -39 -101.5t-96 -43.5q-58 0 -98 43.5t-40 101.5q0 59 39.5 103t98.5 44q58 0 96.5 -44.5t38.5 -102.5z" /> <glyph glyph-name="_439" unicode="" d="M809 532l266 499h-112l-157 -312q-24 -48 -44 -92l-42 92l-155 312h-120l263 -493v-324h101v318zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="uniF1D5" unicode="" horiz-adv-x="1280" d="M842 964q0 -80 -57 -136.5t-136 -56.5q-60 0 -111 35q-62 -67 -115 -146q-247 -371 -202 -859q1 -22 -12.5 -38.5t-34.5 -18.5h-5q-20 0 -35 13.5t-17 33.5q-14 126 -3.5 247.5t29.5 217t54 186t69 155.5t74 125q61 90 132 165q-16 35 -16 77q0 80 56.5 136.5t136.5 56.5 t136.5 -56.5t56.5 -136.5zM1223 953q0 -158 -78 -292t-212.5 -212t-292.5 -78q-64 0 -131 14q-21 5 -32.5 23.5t-6.5 39.5q5 20 23 31.5t39 7.5q51 -13 108 -13q97 0 186 38t153 102t102 153t38 186t-38 186t-102 153t-153 102t-186 38t-186 -38t-153 -102t-102 -153 t-38 -186q0 -114 52 -218q10 -20 3.5 -40t-25.5 -30t-39.5 -3t-30.5 26q-64 123 -64 265q0 119 46.5 227t124.5 186t186 124t226 46q158 0 292.5 -78t212.5 -212.5t78 -292.5z" /> <glyph glyph-name="uniF1D6" unicode="" horiz-adv-x="1792" d="M270 730q-8 19 -8 52q0 20 11 49t24 45q-1 22 7.5 53t22.5 43q0 139 92.5 288.5t217.5 209.5q139 66 324 66q133 0 266 -55q49 -21 90 -48t71 -56t55 -68t42 -74t32.5 -84.5t25.5 -89.5t22 -98l1 -5q55 -83 55 -150q0 -14 -9 -40t-9 -38q0 -1 1.5 -3.5t3.5 -5t2 -3.5 q77 -114 120.5 -214.5t43.5 -208.5q0 -43 -19.5 -100t-55.5 -57q-9 0 -19.5 7.5t-19 17.5t-19 26t-16 26.5t-13.5 26t-9 17.5q-1 1 -3 1l-5 -4q-59 -154 -132 -223q20 -20 61.5 -38.5t69 -41.5t35.5 -65q-2 -4 -4 -16t-7 -18q-64 -97 -302 -97q-53 0 -110.5 9t-98 20 t-104.5 30q-15 5 -23 7q-14 4 -46 4.5t-40 1.5q-41 -45 -127.5 -65t-168.5 -20q-35 0 -69 1.5t-93 9t-101 20.5t-74.5 40t-32.5 64q0 40 10 59.5t41 48.5q11 2 40.5 13t49.5 12q4 0 14 2q2 2 2 4l-2 3q-48 11 -108 105.5t-73 156.5l-5 3q-4 0 -12 -20q-18 -41 -54.5 -74.5 t-77.5 -37.5h-1q-4 0 -6 4.5t-5 5.5q-23 54 -23 100q0 275 252 466z" /> <glyph glyph-name="uniF1D7" unicode="" horiz-adv-x="2048" d="M580 1075q0 41 -25 66t-66 25q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 66 24.5t25 65.5zM1323 568q0 28 -25.5 50t-65.5 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q40 0 65.5 22t25.5 51zM1087 1075q0 41 -24.5 66t-65.5 25 q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 65.5 24.5t24.5 65.5zM1722 568q0 28 -26 50t-65 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q39 0 65 22t26 51zM1456 965q-31 4 -70 4q-169 0 -311 -77t-223.5 -208.5t-81.5 -287.5 q0 -78 23 -152q-35 -3 -68 -3q-26 0 -50 1.5t-55 6.5t-44.5 7t-54.5 10.5t-50 10.5l-253 -127l72 218q-290 203 -290 490q0 169 97.5 311t264 223.5t363.5 81.5q176 0 332.5 -66t262 -182.5t136.5 -260.5zM2048 404q0 -117 -68.5 -223.5t-185.5 -193.5l55 -181l-199 109 q-150 -37 -218 -37q-169 0 -311 70.5t-223.5 191.5t-81.5 264t81.5 264t223.5 191.5t311 70.5q161 0 303 -70.5t227.5 -192t85.5 -263.5z" /> <glyph glyph-name="_443" unicode="" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-453 185l-242 -295q-18 -23 -49 -23q-13 0 -22 4q-19 7 -30.5 23.5t-11.5 36.5v349l864 1059l-1069 -925l-395 162q-37 14 -40 55q-2 40 32 59l1664 960q15 9 32 9q20 0 36 -11z" /> <glyph glyph-name="_444" unicode="" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-527 215l-298 -327q-18 -21 -47 -21q-14 0 -23 4q-19 7 -30 23.5t-11 36.5v452l-472 193q-37 14 -40 55q-3 39 32 59l1664 960q35 21 68 -2zM1422 26l221 1323l-1434 -827l336 -137 l863 639l-478 -797z" /> <glyph glyph-name="_445" unicode="" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298zM896 928v-448q0 -14 -9 -23 t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23z" /> <glyph glyph-name="_446" unicode="" d="M768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="_447" unicode="" horiz-adv-x="1792" d="M1682 -128q-44 0 -132.5 3.5t-133.5 3.5q-44 0 -132 -3.5t-132 -3.5q-24 0 -37 20.5t-13 45.5q0 31 17 46t39 17t51 7t45 15q33 21 33 140l-1 391q0 21 -1 31q-13 4 -50 4h-675q-38 0 -51 -4q-1 -10 -1 -31l-1 -371q0 -142 37 -164q16 -10 48 -13t57 -3.5t45 -15 t20 -45.5q0 -26 -12.5 -48t-36.5 -22q-47 0 -139.5 3.5t-138.5 3.5q-43 0 -128 -3.5t-127 -3.5q-23 0 -35.5 21t-12.5 45q0 30 15.5 45t36 17.5t47.5 7.5t42 15q33 23 33 143l-1 57v813q0 3 0.5 26t0 36.5t-1.5 38.5t-3.5 42t-6.5 36.5t-11 31.5t-16 18q-15 10 -45 12t-53 2 t-41 14t-18 45q0 26 12 48t36 22q46 0 138.5 -3.5t138.5 -3.5q42 0 126.5 3.5t126.5 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17 -43.5t-38.5 -14.5t-49.5 -4t-43 -13q-35 -21 -35 -160l1 -320q0 -21 1 -32q13 -3 39 -3h699q25 0 38 3q1 11 1 32l1 320q0 139 -35 160 q-18 11 -58.5 12.5t-66 13t-25.5 49.5q0 26 12.5 48t37.5 22q44 0 132 -3.5t132 -3.5q43 0 129 3.5t129 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17.5 -44t-40 -14.5t-51.5 -3t-44 -12.5q-35 -23 -35 -161l1 -943q0 -119 34 -140q16 -10 46 -13.5t53.5 -4.5t41.5 -15.5t18 -44.5 q0 -26 -12 -48t-36 -22z" /> <glyph glyph-name="_448" unicode="" horiz-adv-x="1280" d="M1278 1347v-73q0 -29 -18.5 -61t-42.5 -32q-50 0 -54 -1q-26 -6 -32 -31q-3 -11 -3 -64v-1152q0 -25 -18 -43t-43 -18h-108q-25 0 -43 18t-18 43v1218h-143v-1218q0 -25 -17.5 -43t-43.5 -18h-108q-26 0 -43.5 18t-17.5 43v496q-147 12 -245 59q-126 58 -192 179 q-64 117 -64 259q0 166 88 286q88 118 209 159q111 37 417 37h479q25 0 43 -18t18 -43z" /> <glyph glyph-name="_449" unicode="" d="M352 128v-128h-352v128h352zM704 256q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM864 640v-128h-864v128h864zM224 1152v-128h-224v128h224zM1536 128v-128h-736v128h736zM576 1280q26 0 45 -19t19 -45v-256 q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1216 768q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1536 640v-128h-224v128h224zM1536 1152v-128h-864v128h864z" /> <glyph glyph-name="uniF1E0" unicode="" d="M1216 512q133 0 226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5t-226.5 93.5t-93.5 226.5q0 12 2 34l-360 180q-92 -86 -218 -86q-133 0 -226.5 93.5t-93.5 226.5t93.5 226.5t226.5 93.5q126 0 218 -86l360 180q-2 22 -2 34q0 133 93.5 226.5t226.5 93.5 t226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5q-126 0 -218 86l-360 -180q2 -22 2 -34t-2 -34l360 -180q92 86 218 86z" /> <glyph glyph-name="_451" unicode="" d="M1280 341q0 88 -62.5 151t-150.5 63q-84 0 -145 -58l-241 120q2 16 2 23t-2 23l241 120q61 -58 145 -58q88 0 150.5 63t62.5 151t-62.5 150.5t-150.5 62.5t-151 -62.5t-63 -150.5q0 -7 2 -23l-241 -120q-62 57 -145 57q-88 0 -150.5 -62.5t-62.5 -150.5t62.5 -150.5 t150.5 -62.5q83 0 145 57l241 -120q-2 -16 -2 -23q0 -88 63 -150.5t151 -62.5t150.5 62.5t62.5 150.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="_452" unicode="" horiz-adv-x="1792" d="M571 947q-10 25 -34 35t-49 0q-108 -44 -191 -127t-127 -191q-10 -25 0 -49t35 -34q13 -5 24 -5q42 0 60 40q34 84 98.5 148.5t148.5 98.5q25 11 35 35t0 49zM1513 1303l46 -46l-244 -243l68 -68q19 -19 19 -45.5t-19 -45.5l-64 -64q89 -161 89 -343q0 -143 -55.5 -273.5 t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5q182 0 343 -89l64 64q19 19 45.5 19t45.5 -19l68 -68zM1521 1359q-10 -10 -22 -10q-13 0 -23 10l-91 90q-9 10 -9 23t9 23q10 9 23 9t23 -9l90 -91 q10 -9 10 -22.5t-10 -22.5zM1751 1129q-11 -9 -23 -9t-23 9l-90 91q-10 9 -10 22.5t10 22.5q9 10 22.5 10t22.5 -10l91 -90q9 -10 9 -23t-9 -23zM1792 1312q0 -14 -9 -23t-23 -9h-96q-14 0 -23 9t-9 23t9 23t23 9h96q14 0 23 -9t9 -23zM1600 1504v-96q0 -14 -9 -23t-23 -9 t-23 9t-9 23v96q0 14 9 23t23 9t23 -9t9 -23zM1751 1449l-91 -90q-10 -10 -22 -10q-13 0 -23 10q-10 9 -10 22.5t10 22.5l90 91q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" /> <glyph glyph-name="_453" unicode="" horiz-adv-x="1792" d="M609 720l287 208l287 -208l-109 -336h-355zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM1515 186q149 203 149 454v3l-102 -89l-240 224l63 323 l134 -12q-150 206 -389 282l53 -124l-287 -159l-287 159l53 124q-239 -76 -389 -282l135 12l62 -323l-240 -224l-102 89v-3q0 -251 149 -454l30 132l326 -40l139 -298l-116 -69q117 -39 240 -39t240 39l-116 69l139 298l326 40z" /> <glyph glyph-name="_454" unicode="" horiz-adv-x="1792" d="M448 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM256 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM832 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM66 768q-28 0 -47 19t-19 46v129h514v-129q0 -27 -19 -46t-46 -19h-383zM1216 224v-192q0 -14 -9 -23t-23 -9h-192 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1600 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23 zM1408 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1016v-13h-514v10q0 104 -382 102q-382 -1 -382 -102v-10h-514v13q0 17 8.5 43t34 64t65.5 75.5t110.5 76t160 67.5t224 47.5t293.5 18.5t293 -18.5t224 -47.5 t160.5 -67.5t110.5 -76t65.5 -75.5t34 -64t8.5 -43zM1792 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 962v-129q0 -27 -19 -46t-46 -19h-384q-27 0 -46 19t-19 46v129h514z" /> <glyph glyph-name="_455" unicode="" horiz-adv-x="1792" d="M704 1216v-768q0 -26 -19 -45t-45 -19v-576q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v512l249 873q7 23 31 23h424zM1024 1216v-704h-256v704h256zM1792 320v-512q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v576q-26 0 -45 19t-19 45v768h424q24 0 31 -23z M736 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23zM1408 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23z" /> <glyph glyph-name="_456" unicode="" horiz-adv-x="1792" d="M1755 1083q37 -38 37 -90.5t-37 -90.5l-401 -400l150 -150l-160 -160q-163 -163 -389.5 -186.5t-411.5 100.5l-362 -362h-181v181l362 362q-124 185 -100.5 411.5t186.5 389.5l160 160l150 -150l400 401q38 37 91 37t90 -37t37 -90.5t-37 -90.5l-400 -401l234 -234 l401 400q38 37 91 37t90 -37z" /> <glyph glyph-name="_457" unicode="" horiz-adv-x="1792" d="M873 796q0 -83 -63.5 -142.5t-152.5 -59.5t-152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59t152.5 -59t63.5 -143zM1375 796q0 -83 -63 -142.5t-153 -59.5q-89 0 -152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59q90 0 153 -59t63 -143zM1600 616v667q0 87 -32 123.5 t-111 36.5h-1112q-83 0 -112.5 -34t-29.5 -126v-673q43 -23 88.5 -40t81 -28t81 -18.5t71 -11t70 -4t58.5 -0.5t56.5 2t44.5 2q68 1 95 -27q6 -6 10 -9q26 -25 61 -51q7 91 118 87q5 0 36.5 -1.5t43 -2t45.5 -1t53 1t54.5 4.5t61 8.5t62 13.5t67 19.5t67.5 27t72 34.5z M1763 621q-121 -149 -372 -252q84 -285 -23 -465q-66 -113 -183 -148q-104 -32 -182 15q-86 51 -82 164l-1 326v1q-8 2 -24.5 6t-23.5 5l-1 -338q4 -114 -83 -164q-79 -47 -183 -15q-117 36 -182 150q-105 180 -22 463q-251 103 -372 252q-25 37 -4 63t60 -1q4 -2 11.5 -7 t10.5 -8v694q0 72 47 123t114 51h1257q67 0 114 -51t47 -123v-694l21 15q39 27 60 1t-4 -63z" /> <glyph glyph-name="_458" unicode="" horiz-adv-x="1792" d="M896 1102v-434h-145v434h145zM1294 1102v-434h-145v434h145zM1294 342l253 254v795h-1194v-1049h326v-217l217 217h398zM1692 1536v-1013l-434 -434h-326l-217 -217h-217v217h-398v1158l109 289h1483z" /> <glyph glyph-name="_459" unicode="" d="M773 217v-127q-1 -292 -6 -305q-12 -32 -51 -40q-54 -9 -181.5 38t-162.5 89q-13 15 -17 36q-1 12 4 26q4 10 34 47t181 216q1 0 60 70q15 19 39.5 24.5t49.5 -3.5q24 -10 37.5 -29t12.5 -42zM624 468q-3 -55 -52 -70l-120 -39q-275 -88 -292 -88q-35 2 -54 36 q-12 25 -17 75q-8 76 1 166.5t30 124.5t56 32q13 0 202 -77q71 -29 115 -47l84 -34q23 -9 35.5 -30.5t11.5 -48.5zM1450 171q-7 -54 -91.5 -161t-135.5 -127q-37 -14 -63 7q-14 10 -184 287l-47 77q-14 21 -11.5 46t19.5 46q35 43 83 26q1 -1 119 -40q203 -66 242 -79.5 t47 -20.5q28 -22 22 -61zM778 803q5 -102 -54 -122q-58 -17 -114 71l-378 598q-8 35 19 62q41 43 207.5 89.5t224.5 31.5q40 -10 49 -45q3 -18 22 -305.5t24 -379.5zM1440 695q3 -39 -26 -59q-15 -10 -329 -86q-67 -15 -91 -23l1 2q-23 -6 -46 4t-37 32q-30 47 0 87 q1 1 75 102q125 171 150 204t34 39q28 19 65 2q48 -23 123 -133.5t81 -167.5v-3z" /> <glyph glyph-name="_460" unicode="" horiz-adv-x="2048" d="M1024 1024h-384v-384h384v384zM1152 384v-128h-640v128h640zM1152 1152v-640h-640v640h640zM1792 384v-128h-512v128h512zM1792 640v-128h-512v128h512zM1792 896v-128h-512v128h512zM1792 1152v-128h-512v128h512zM256 192v960h-128v-960q0 -26 19 -45t45 -19t45 19 t19 45zM1920 192v1088h-1536v-1088q0 -33 -11 -64h1483q26 0 45 19t19 45zM2048 1408v-1216q0 -80 -56 -136t-136 -56h-1664q-80 0 -136 56t-56 136v1088h256v128h1792z" /> <glyph glyph-name="_461" unicode="" horiz-adv-x="2048" d="M1024 13q-20 0 -93 73.5t-73 93.5q0 32 62.5 54t103.5 22t103.5 -22t62.5 -54q0 -20 -73 -93.5t-93 -73.5zM1294 284q-2 0 -40 25t-101.5 50t-128.5 25t-128.5 -25t-101 -50t-40.5 -25q-18 0 -93.5 75t-75.5 93q0 13 10 23q78 77 196 121t233 44t233 -44t196 -121 q10 -10 10 -23q0 -18 -75.5 -93t-93.5 -75zM1567 556q-11 0 -23 8q-136 105 -252 154.5t-268 49.5q-85 0 -170.5 -22t-149 -53t-113.5 -62t-79 -53t-31 -22q-17 0 -92 75t-75 93q0 12 10 22q132 132 320 205t380 73t380 -73t320 -205q10 -10 10 -22q0 -18 -75 -93t-92 -75z M1838 827q-11 0 -22 9q-179 157 -371.5 236.5t-420.5 79.5t-420.5 -79.5t-371.5 -236.5q-11 -9 -22 -9q-17 0 -92.5 75t-75.5 93q0 13 10 23q187 186 445 288t527 102t527 -102t445 -288q10 -10 10 -23q0 -18 -75.5 -93t-92.5 -75z" /> <glyph glyph-name="_462" unicode="" horiz-adv-x="1792" d="M384 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5 t37.5 90.5zM384 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 768q0 53 -37.5 90.5t-90.5 37.5 t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1536 0v384q0 52 -38 90t-90 38t-90 -38t-38 -90v-384q0 -52 38 -90t90 -38t90 38t38 90zM1152 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z M1536 1088v256q0 26 -19 45t-45 19h-1280q-26 0 -45 -19t-19 -45v-256q0 -26 19 -45t45 -19h1280q26 0 45 19t19 45zM1536 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1408v-1536q0 -52 -38 -90t-90 -38 h-1408q-52 0 -90 38t-38 90v1536q0 52 38 90t90 38h1408q52 0 90 -38t38 -90z" /> <glyph glyph-name="_463" unicode="" d="M1519 890q18 -84 -4 -204q-87 -444 -565 -444h-44q-25 0 -44 -16.5t-24 -42.5l-4 -19l-55 -346l-2 -15q-5 -26 -24.5 -42.5t-44.5 -16.5h-251q-21 0 -33 15t-9 36q9 56 26.5 168t26.5 168t27 167.5t27 167.5q5 37 43 37h131q133 -2 236 21q175 39 287 144q102 95 155 246 q24 70 35 133q1 6 2.5 7.5t3.5 1t6 -3.5q79 -59 98 -162zM1347 1172q0 -107 -46 -236q-80 -233 -302 -315q-113 -40 -252 -42q0 -1 -90 -1l-90 1q-100 0 -118 -96q-2 -8 -85 -530q-1 -10 -12 -10h-295q-22 0 -36.5 16.5t-11.5 38.5l232 1471q5 29 27.5 48t51.5 19h598 q34 0 97.5 -13t111.5 -32q107 -41 163.5 -123t56.5 -196z" /> <glyph glyph-name="_464" unicode="" horiz-adv-x="1792" d="M441 864q33 0 52 -26q266 -364 362 -774h-446q-127 441 -367 749q-12 16 -3 33.5t29 17.5h373zM1000 507q-49 -199 -125 -393q-79 310 -256 594q40 221 44 449q211 -340 337 -650zM1099 1216q235 -324 384.5 -698.5t184.5 -773.5h-451q-41 665 -553 1472h435zM1792 640 q0 -424 -101 -812q-67 560 -359 1083q-25 301 -106 584q-4 16 5.5 28.5t25.5 12.5h359q21 0 38.5 -13t22.5 -33q115 -409 115 -850z" /> <glyph glyph-name="uniF1F0" unicode="" horiz-adv-x="2304" d="M1975 546h-138q14 37 66 179l3 9q4 10 10 26t9 26l12 -55zM531 611l-58 295q-11 54 -75 54h-268l-2 -13q311 -79 403 -336zM710 960l-162 -438l-17 89q-26 70 -85 129.5t-131 88.5l135 -510h175l261 641h-176zM849 318h166l104 642h-166zM1617 944q-69 27 -149 27 q-123 0 -201 -59t-79 -153q-1 -102 145 -174q48 -23 67 -41t19 -39q0 -30 -30 -46t-69 -16q-86 0 -156 33l-22 11l-23 -144q74 -34 185 -34q130 -1 208.5 59t80.5 160q0 106 -140 174q-49 25 -71 42t-22 38q0 22 24.5 38.5t70.5 16.5q70 1 124 -24l15 -8zM2042 960h-128 q-65 0 -87 -54l-246 -588h174l35 96h212q5 -22 20 -96h154zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" /> <glyph glyph-name="_466" unicode="" horiz-adv-x="2304" d="M1119 1195q-128 85 -281 85q-103 0 -197.5 -40.5t-162.5 -108.5t-108.5 -162t-40.5 -197q0 -104 40.5 -198t108.5 -162t162 -108.5t198 -40.5q153 0 281 85q-131 107 -178 265.5t0.5 316.5t177.5 265zM1152 1171q-126 -99 -172 -249.5t-0.5 -300.5t172.5 -249 q127 99 172.5 249t-0.5 300.5t-172 249.5zM1185 1195q130 -107 177.5 -265.5t0.5 -317t-178 -264.5q128 -85 281 -85q104 0 198 40.5t162 108.5t108.5 162t40.5 198q0 103 -40.5 197t-108.5 162t-162.5 108.5t-197.5 40.5q-153 0 -281 -85zM1926 473h7v3h-17v-3h7v-17h3v17z M1955 456h4v20h-5l-6 -13l-6 13h-5v-20h3v15l6 -13h4l5 13v-15zM1947 16v-2h-2h-3v3h3h2v-1zM1947 7h3l-4 5h2l1 1q1 1 1 3t-1 3l-1 1h-3h-6v-13h3v5h1zM685 75q0 19 11 31t30 12q18 0 29 -12.5t11 -30.5q0 -19 -11 -31t-29 -12q-19 0 -30 12t-11 31zM1158 119q30 0 35 -32 h-70q5 32 35 32zM1514 75q0 19 11 31t29 12t29.5 -12.5t11.5 -30.5q0 -19 -11 -31t-30 -12q-18 0 -29 12t-11 31zM1786 75q0 18 11.5 30.5t29.5 12.5t29.5 -12.5t11.5 -30.5q0 -19 -11.5 -31t-29.5 -12t-29.5 12.5t-11.5 30.5zM1944 3q-2 0 -4 1q-1 0 -3 2t-2 3q-1 2 -1 4 q0 3 1 4q0 2 2 4l1 1q2 0 2 1q2 1 4 1q3 0 4 -1l4 -2l2 -4v-1q1 -2 1 -3l-1 -1v-3t-1 -1l-1 -2q-2 -2 -4 -2q-1 -1 -4 -1zM599 7h30v85q0 24 -14.5 38.5t-39.5 15.5q-32 0 -47 -24q-14 24 -45 24q-24 0 -39 -20v16h-30v-135h30v75q0 36 33 36q30 0 30 -36v-75h29v75 q0 36 33 36q30 0 30 -36v-75zM765 7h29v68v67h-29v-16q-17 20 -43 20q-29 0 -48 -20t-19 -51t19 -51t48 -20q28 0 43 20v-17zM943 48q0 34 -47 40l-14 2q-23 4 -23 14q0 15 25 15q23 0 43 -11l12 24q-22 14 -55 14q-26 0 -41 -12t-15 -32q0 -33 47 -39l13 -2q24 -4 24 -14 q0 -17 -31 -17q-25 0 -45 14l-13 -23q25 -17 58 -17q29 0 45.5 12t16.5 32zM1073 14l-8 25q-13 -7 -26 -7q-19 0 -19 22v61h48v27h-48v41h-30v-41h-28v-27h28v-61q0 -50 47 -50q21 0 36 10zM1159 146q-29 0 -48 -20t-19 -51q0 -32 19.5 -51.5t49.5 -19.5q33 0 55 19l-14 22 q-18 -15 -39 -15q-34 0 -41 33h101v12q0 32 -18 51.5t-46 19.5zM1318 146q-23 0 -35 -20v16h-30v-135h30v76q0 35 29 35q10 0 18 -4l9 28q-9 4 -21 4zM1348 75q0 -31 19.5 -51t52.5 -20q29 0 48 16l-14 24q-18 -13 -35 -12q-18 0 -29.5 12t-11.5 31t11.5 31t29.5 12 q19 0 35 -12l14 24q-20 16 -48 16q-33 0 -52.5 -20t-19.5 -51zM1593 7h30v68v67h-30v-16q-15 20 -42 20q-29 0 -48.5 -20t-19.5 -51t19.5 -51t48.5 -20q28 0 42 20v-17zM1726 146q-23 0 -35 -20v16h-29v-135h29v76q0 35 29 35q10 0 18 -4l9 28q-8 4 -21 4zM1866 7h29v68v122 h-29v-71q-15 20 -43 20t-47.5 -20.5t-19.5 -50.5t19.5 -50.5t47.5 -20.5q29 0 43 20v-17zM1944 27l-2 -1h-3q-2 -1 -4 -3q-3 -1 -3 -4q-1 -2 -1 -6q0 -3 1 -5q0 -2 3 -4q2 -2 4 -3t5 -1q4 0 6 1q0 1 2 2l2 1q1 1 3 4q1 2 1 5q0 4 -1 6q-1 1 -3 4q0 1 -2 2l-2 1q-1 0 -3 0.5 t-3 0.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" /> <glyph glyph-name="_467" unicode="" horiz-adv-x="2304" d="M313 759q0 -51 -36 -84q-29 -26 -89 -26h-17v220h17q61 0 89 -27q36 -31 36 -83zM2089 824q0 -52 -64 -52h-19v101h20q63 0 63 -49zM380 759q0 74 -50 120.5t-129 46.5h-95v-333h95q74 0 119 38q60 51 60 128zM410 593h65v333h-65v-333zM730 694q0 40 -20.5 62t-75.5 42 q-29 10 -39.5 19t-10.5 23q0 16 13.5 26.5t34.5 10.5q29 0 53 -27l34 44q-41 37 -98 37q-44 0 -74 -27.5t-30 -67.5q0 -35 18 -55.5t64 -36.5q37 -13 45 -19q19 -12 19 -34q0 -20 -14 -33.5t-36 -13.5q-48 0 -71 44l-42 -40q44 -64 115 -64q51 0 83 30.5t32 79.5zM1008 604 v77q-37 -37 -78 -37q-49 0 -80.5 32.5t-31.5 82.5q0 48 31.5 81.5t77.5 33.5q43 0 81 -38v77q-40 20 -80 20q-74 0 -125.5 -50.5t-51.5 -123.5t51 -123.5t125 -50.5q42 0 81 19zM2240 0v527q-65 -40 -144.5 -84t-237.5 -117t-329.5 -137.5t-417.5 -134.5t-504 -118h1569 q26 0 45 19t19 45zM1389 757q0 75 -53 128t-128 53t-128 -53t-53 -128t53 -128t128 -53t128 53t53 128zM1541 584l144 342h-71l-90 -224l-89 224h-71l142 -342h35zM1714 593h184v56h-119v90h115v56h-115v74h119v57h-184v-333zM2105 593h80l-105 140q76 16 76 94q0 47 -31 73 t-87 26h-97v-333h65v133h9zM2304 1274v-1268q0 -56 -38.5 -95t-93.5 -39h-2040q-55 0 -93.5 39t-38.5 95v1268q0 56 38.5 95t93.5 39h2040q55 0 93.5 -39t38.5 -95z" /> <glyph glyph-name="f1f3" unicode="" horiz-adv-x="2304" d="M119 854h89l-45 108zM740 328l74 79l-70 79h-163v-49h142v-55h-142v-54h159zM898 406l99 -110v217zM1186 453q0 33 -40 33h-84v-69h83q41 0 41 36zM1475 457q0 29 -42 29h-82v-61h81q43 0 43 32zM1197 923q0 29 -42 29h-82v-60h81q43 0 43 31zM1656 854h89l-44 108z M699 1009v-271h-66v212l-94 -212h-57l-94 212v-212h-132l-25 60h-135l-25 -60h-70l116 271h96l110 -257v257h106l85 -184l77 184h108zM1255 453q0 -20 -5.5 -35t-14 -25t-22.5 -16.5t-26 -10t-31.5 -4.5t-31.5 -1t-32.5 0.5t-29.5 0.5v-91h-126l-80 90l-83 -90h-256v271h260 l80 -89l82 89h207q109 0 109 -89zM964 794v-56h-217v271h217v-57h-152v-49h148v-55h-148v-54h152zM2304 235v-229q0 -55 -38.5 -94.5t-93.5 -39.5h-2040q-55 0 -93.5 39.5t-38.5 94.5v678h111l25 61h55l25 -61h218v46l19 -46h113l20 47v-47h541v99l10 1q10 0 10 -14v-86h279 v23q23 -12 55 -18t52.5 -6.5t63 0.5t51.5 1l25 61h56l25 -61h227v58l34 -58h182v378h-180v-44l-25 44h-185v-44l-23 44h-249q-69 0 -109 -22v22h-172v-22q-24 22 -73 22h-628l-43 -97l-43 97h-198v-44l-22 44h-169l-78 -179v391q0 55 38.5 94.5t93.5 39.5h2040 q55 0 93.5 -39.5t38.5 -94.5v-678h-120q-51 0 -81 -22v22h-177q-55 0 -78 -22v22h-316v-22q-31 22 -87 22h-209v-22q-23 22 -91 22h-234l-54 -58l-50 58h-349v-378h343l55 59l52 -59h211v89h21q59 0 90 13v-102h174v99h8q8 0 10 -2t2 -10v-87h529q57 0 88 24v-24h168 q60 0 95 17zM1546 469q0 -23 -12 -43t-34 -29q25 -9 34 -26t9 -46v-54h-65v45q0 33 -12 43.5t-46 10.5h-69v-99h-65v271h154q48 0 77 -15t29 -58zM1269 936q0 -24 -12.5 -44t-33.5 -29q26 -9 34.5 -25.5t8.5 -46.5v-53h-65q0 9 0.5 26.5t0 25t-3 18.5t-8.5 16t-17.5 8.5 t-29.5 3.5h-70v-98h-64v271l153 -1q49 0 78 -14.5t29 -57.5zM1798 327v-56h-216v271h216v-56h-151v-49h148v-55h-148v-54zM1372 1009v-271h-66v271h66zM2065 357q0 -86 -102 -86h-126v58h126q34 0 34 25q0 16 -17 21t-41.5 5t-49.5 3.5t-42 22.5t-17 55q0 39 26 60t66 21 h130v-57h-119q-36 0 -36 -25q0 -16 17.5 -20.5t42 -4t49 -2.5t42 -21.5t17.5 -54.5zM2304 407v-101q-24 -35 -88 -35h-125v58h125q33 0 33 25q0 13 -12.5 19t-31 5.5t-40 2t-40 8t-31 24t-12.5 48.5q0 39 26.5 60t66.5 21h129v-57h-118q-36 0 -36 -25q0 -20 29 -22t68.5 -5 t56.5 -26zM2139 1008v-270h-92l-122 203v-203h-132l-26 60h-134l-25 -60h-75q-129 0 -129 133q0 138 133 138h63v-59q-7 0 -28 1t-28.5 0.5t-23 -2t-21.5 -6.5t-14.5 -13.5t-11.5 -23t-3 -33.5q0 -38 13.5 -58t49.5 -20h29l92 213h97l109 -256v256h99l114 -188v188h66z" /> <glyph glyph-name="_469" unicode="" horiz-adv-x="2304" d="M745 630q0 -37 -25.5 -61.5t-62.5 -24.5q-29 0 -46.5 16t-17.5 44q0 37 25 62.5t62 25.5q28 0 46.5 -16.5t18.5 -45.5zM1530 779q0 -42 -22 -57t-66 -15l-32 -1l17 107q2 11 13 11h18q22 0 35 -2t25 -12.5t12 -30.5zM1881 630q0 -36 -25.5 -61t-61.5 -25q-29 0 -47 16 t-18 44q0 37 25 62.5t62 25.5q28 0 46.5 -16.5t18.5 -45.5zM513 801q0 59 -38.5 85.5t-100.5 26.5h-160q-19 0 -21 -19l-65 -408q-1 -6 3 -11t10 -5h76q20 0 22 19l18 110q1 8 7 13t15 6.5t17 1.5t19 -1t14 -1q86 0 135 48.5t49 134.5zM822 489l41 261q1 6 -3 11t-10 5h-76 q-14 0 -17 -33q-27 40 -95 40q-72 0 -122.5 -54t-50.5 -127q0 -59 34.5 -94t92.5 -35q28 0 58 12t48 32q-4 -12 -4 -21q0 -16 13 -16h69q19 0 22 19zM1269 752q0 5 -4 9.5t-9 4.5h-77q-11 0 -18 -10l-106 -156l-44 150q-5 16 -22 16h-75q-5 0 -9 -4.5t-4 -9.5q0 -2 19.5 -59 t42 -123t23.5 -70q-82 -112 -82 -120q0 -13 13 -13h77q11 0 18 10l255 368q2 2 2 7zM1649 801q0 59 -38.5 85.5t-100.5 26.5h-159q-20 0 -22 -19l-65 -408q-1 -6 3 -11t10 -5h82q12 0 16 13l18 116q1 8 7 13t15 6.5t17 1.5t19 -1t14 -1q86 0 135 48.5t49 134.5zM1958 489 l41 261q1 6 -3 11t-10 5h-76q-14 0 -17 -33q-26 40 -95 40q-72 0 -122.5 -54t-50.5 -127q0 -59 34.5 -94t92.5 -35q29 0 59 12t47 32q0 -1 -2 -9t-2 -12q0 -16 13 -16h69q19 0 22 19zM2176 898v1q0 14 -13 14h-74q-11 0 -13 -11l-65 -416l-1 -2q0 -5 4 -9.5t10 -4.5h66 q19 0 21 19zM392 764q-5 -35 -26 -46t-60 -11l-33 -1l17 107q2 11 13 11h19q40 0 58 -11.5t12 -48.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" /> <glyph glyph-name="_470" unicode="" horiz-adv-x="2304" d="M1597 633q0 -69 -21 -106q-19 -35 -52 -35q-23 0 -41 9v224q29 30 57 30q57 0 57 -122zM2035 669h-110q6 98 56 98q51 0 54 -98zM476 534q0 59 -33 91.5t-101 57.5q-36 13 -52 24t-16 25q0 26 38 26q58 0 124 -33l18 112q-67 32 -149 32q-77 0 -123 -38q-48 -39 -48 -109 q0 -58 32.5 -90.5t99.5 -56.5q39 -14 54.5 -25.5t15.5 -27.5q0 -31 -48 -31q-29 0 -70 12.5t-72 30.5l-18 -113q72 -41 168 -41q81 0 129 37q51 41 51 117zM771 749l19 111h-96v135l-129 -21l-18 -114l-46 -8l-17 -103h62v-219q0 -84 44 -120q38 -30 111 -30q32 0 79 11v118 q-32 -7 -44 -7q-42 0 -42 50v197h77zM1087 724v139q-15 3 -28 3q-32 0 -55.5 -16t-33.5 -46l-10 56h-131v-471h150v306q26 31 82 31q16 0 26 -2zM1124 389h150v471h-150v-471zM1746 638q0 122 -45 179q-40 52 -111 52q-64 0 -117 -56l-8 47h-132v-645l150 25v151 q36 -11 68 -11q83 0 134 56q61 65 61 202zM1278 986q0 33 -23 56t-56 23t-56 -23t-23 -56t23 -56.5t56 -23.5t56 23.5t23 56.5zM2176 629q0 113 -48 176q-50 64 -144 64q-96 0 -151.5 -66t-55.5 -180q0 -128 63 -188q55 -55 161 -55q101 0 160 40l-16 103q-57 -31 -128 -31 q-43 0 -63 19q-23 19 -28 66h248q2 14 2 52zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" /> <glyph glyph-name="_471" unicode="" horiz-adv-x="2048" d="M1558 684q61 -356 298 -556q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5zM1024 -176q16 0 16 16t-16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5zM2026 1424q8 -10 7.5 -23.5t-10.5 -22.5 l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5 l418 363q10 8 23.5 7t21.5 -11z" /> <glyph glyph-name="_472" unicode="" horiz-adv-x="2048" d="M1040 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM503 315l877 760q-42 88 -132.5 146.5t-223.5 58.5q-93 0 -169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -384 -137 -645zM1856 128 q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5l149 129h757q-166 187 -227 459l111 97q61 -356 298 -556zM1942 1520l84 -96q8 -10 7.5 -23.5t-10.5 -22.5l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161 q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5l418 363q10 8 23.5 7t21.5 -11z" /> <glyph glyph-name="_473" unicode="" horiz-adv-x="1408" d="M512 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM768 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1024 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704 q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167 q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" /> <glyph glyph-name="_474" unicode="" d="M1150 462v-109q0 -50 -36.5 -89t-94 -60.5t-118 -32.5t-117.5 -11q-205 0 -342.5 139t-137.5 346q0 203 136 339t339 136q34 0 75.5 -4.5t93 -18t92.5 -34t69 -56.5t28 -81v-109q0 -16 -16 -16h-118q-16 0 -16 16v70q0 43 -65.5 67.5t-137.5 24.5q-140 0 -228.5 -91.5 t-88.5 -237.5q0 -151 91.5 -249.5t233.5 -98.5q68 0 138 24t70 66v70q0 7 4.5 11.5t10.5 4.5h119q6 0 11 -4.5t5 -11.5zM768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5 t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="_475" unicode="" d="M972 761q0 108 -53.5 169t-147.5 61q-63 0 -124 -30.5t-110 -84.5t-79.5 -137t-30.5 -180q0 -112 53.5 -173t150.5 -61q96 0 176 66.5t122.5 166t42.5 203.5zM1536 640q0 -111 -37 -197t-98.5 -135t-131.5 -74.5t-145 -27.5q-6 0 -15.5 -0.5t-16.5 -0.5q-95 0 -142 53 q-28 33 -33 83q-52 -66 -131.5 -110t-173.5 -44q-161 0 -249.5 95.5t-88.5 269.5q0 157 66 290t179 210.5t246 77.5q87 0 155 -35.5t106 -99.5l2 19l11 56q1 6 5.5 12t9.5 6h118q5 0 13 -11q5 -5 3 -16l-120 -614q-5 -24 -5 -48q0 -39 12.5 -52t44.5 -13q28 1 57 5.5t73 24 t77 50t57 89.5t24 137q0 292 -174 466t-466 174q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51q228 0 405 144q11 9 24 8t21 -12l41 -49q8 -12 7 -24q-2 -13 -12 -22q-102 -83 -227.5 -128t-258.5 -45q-156 0 -298 61 t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q344 0 556 -212t212 -556z" /> <glyph glyph-name="_476" unicode="" horiz-adv-x="1792" d="M1698 1442q94 -94 94 -226.5t-94 -225.5l-225 -223l104 -104q10 -10 10 -23t-10 -23l-210 -210q-10 -10 -23 -10t-23 10l-105 105l-603 -603q-37 -37 -90 -37h-203l-256 -128l-64 64l128 256v203q0 53 37 90l603 603l-105 105q-10 10 -10 23t10 23l210 210q10 10 23 10 t23 -10l104 -104l223 225q93 94 225.5 94t226.5 -94zM512 64l576 576l-192 192l-576 -576v-192h192z" /> <glyph glyph-name="f1fc" unicode="" horiz-adv-x="1792" d="M1615 1536q70 0 122.5 -46.5t52.5 -116.5q0 -63 -45 -151q-332 -629 -465 -752q-97 -91 -218 -91q-126 0 -216.5 92.5t-90.5 219.5q0 128 92 212l638 579q59 54 130 54zM706 502q39 -76 106.5 -130t150.5 -76l1 -71q4 -213 -129.5 -347t-348.5 -134q-123 0 -218 46.5 t-152.5 127.5t-86.5 183t-29 220q7 -5 41 -30t62 -44.5t59 -36.5t46 -17q41 0 55 37q25 66 57.5 112.5t69.5 76t88 47.5t103 25.5t125 10.5z" /> <glyph glyph-name="_478" unicode="" horiz-adv-x="1792" d="M1792 128v-384h-1792v384q45 0 85 14t59 27.5t47 37.5q30 27 51.5 38t56.5 11q24 0 44 -7t31 -15t33 -27q29 -25 47 -38t58 -27t86 -14q45 0 85 14.5t58 27t48 37.5q21 19 32.5 27t31 15t43.5 7q35 0 56.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14t85 14t59 27.5 t47 37.5q30 27 51.5 38t56.5 11q34 0 55.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14zM1792 448v-192q-24 0 -44 7t-31 15t-33 27q-29 25 -47 38t-58 27t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-22 -19 -33 -27t-31 -15t-44 -7q-35 0 -56.5 11t-51.5 38q-29 25 -47 38 t-58 27t-86 14q-45 0 -85 -14.5t-58 -27t-48 -37.5q-21 -19 -32.5 -27t-31 -15t-43.5 -7q-35 0 -56.5 11t-51.5 38q-28 24 -47 37.5t-59 27.5t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-30 -27 -51.5 -38t-56.5 -11v192q0 80 56 136t136 56h64v448h256v-448h256v448h256v-448 h256v448h256v-448h64q80 0 136 -56t56 -136zM512 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1024 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5 q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1536 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150z" /> <glyph glyph-name="_479" unicode="" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1664 1024l256 -896h-1664v576l448 576l576 -576z" /> <glyph glyph-name="_480" unicode="" horiz-adv-x="1792" d="M768 646l546 -546q-106 -108 -247.5 -168t-298.5 -60q-209 0 -385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103v-762zM955 640h773q0 -157 -60 -298.5t-168 -247.5zM1664 768h-768v768q209 0 385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="_481" unicode="" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1920 1248v-435q0 -21 -19.5 -29.5t-35.5 7.5l-121 121l-633 -633q-10 -10 -23 -10t-23 10l-233 233l-416 -416l-192 192l585 585q10 10 23 10t23 -10l233 -233l464 464l-121 121q-16 16 -7.5 35.5t29.5 19.5h435q14 0 23 -9 t9 -23z" /> <glyph glyph-name="_482" unicode="" horiz-adv-x="1792" d="M1292 832q0 -6 10 -41q10 -29 25 -49.5t41 -34t44 -20t55 -16.5q325 -91 325 -332q0 -146 -105.5 -242.5t-254.5 -96.5q-59 0 -111.5 18.5t-91.5 45.5t-77 74.5t-63 87.5t-53.5 103.5t-43.5 103t-39.5 106.5t-35.5 95q-32 81 -61.5 133.5t-73.5 96.5t-104 64t-142 20 q-96 0 -183 -55.5t-138 -144.5t-51 -185q0 -160 106.5 -279.5t263.5 -119.5q177 0 258 95q56 63 83 116l84 -152q-15 -34 -44 -70l1 -1q-131 -152 -388 -152q-147 0 -269.5 79t-190.5 207.5t-68 274.5q0 105 43.5 206t116 176.5t172 121.5t204.5 46q87 0 159 -19t123.5 -50 t95 -80t72.5 -99t58.5 -117t50.5 -124.5t50 -130.5t55 -127q96 -200 233 -200q81 0 138.5 48.5t57.5 128.5q0 42 -19 72t-50.5 46t-72.5 31.5t-84.5 27t-87.5 34t-81 52t-65 82t-39 122.5q-3 16 -3 33q0 110 87.5 192t198.5 78q78 -3 120.5 -14.5t90.5 -53.5h-1 q12 -11 23 -24.5t26 -36t19 -27.5l-129 -99q-26 49 -54 70v1q-23 21 -97 21q-49 0 -84 -33t-35 -83z" /> <glyph glyph-name="_483" unicode="" d="M1432 484q0 173 -234 239q-35 10 -53 16.5t-38 25t-29 46.5q0 2 -2 8.5t-3 12t-1 7.5q0 36 24.5 59.5t60.5 23.5q54 0 71 -15h-1q20 -15 39 -51l93 71q-39 54 -49 64q-33 29 -67.5 39t-85.5 10q-80 0 -142 -57.5t-62 -137.5q0 -7 2 -23q16 -96 64.5 -140t148.5 -73 q29 -8 49 -15.5t45 -21.5t38.5 -34.5t13.5 -46.5v-5q1 -58 -40.5 -93t-100.5 -35q-97 0 -167 144q-23 47 -51.5 121.5t-48 125.5t-54 110.5t-74 95.5t-103.5 60.5t-147 24.5q-101 0 -192 -56t-144 -148t-50 -192v-1q4 -108 50.5 -199t133.5 -147.5t196 -56.5q186 0 279 110 q20 27 31 51l-60 109q-42 -80 -99 -116t-146 -36q-115 0 -191 87t-76 204q0 105 82 189t186 84q112 0 170 -53.5t104 -172.5q8 -21 25.5 -68.5t28.5 -76.5t31.5 -74.5t38.5 -74t45.5 -62.5t55.5 -53.5t66 -33t80 -13.5q107 0 183 69.5t76 174.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="_484" unicode="" horiz-adv-x="2048" d="M1152 640q0 104 -40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM1920 640q0 104 -40.5 198.5 t-109.5 163.5t-163.5 109.5t-198.5 40.5h-386q119 -90 188.5 -224t69.5 -288t-69.5 -288t-188.5 -224h386q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM2048 640q0 -130 -51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5 t-136.5 204t-51 248.5t51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5z" /> <glyph glyph-name="_485" unicode="" horiz-adv-x="2048" d="M0 640q0 130 51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5t-51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5t-136.5 204t-51 248.5zM1408 128q104 0 198.5 40.5t163.5 109.5 t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5z" /> <glyph glyph-name="_486" unicode="" horiz-adv-x="2304" d="M762 384h-314q-40 0 -57.5 35t6.5 67l188 251q-65 31 -137 31q-132 0 -226 -94t-94 -226t94 -226t226 -94q115 0 203 72.5t111 183.5zM576 512h186q-18 85 -75 148zM1056 512l288 384h-480l-99 -132q105 -103 126 -252h165zM2176 448q0 132 -94 226t-226 94 q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94t226 94t94 226zM2304 448q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 97 39.5 183.5t109.5 149.5l-65 98l-353 -469 q-18 -26 -51 -26h-197q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q114 0 215 -55l137 183h-224q-26 0 -45 19t-19 45t19 45t45 19h384v-128h435l-85 128h-222q-26 0 -45 19t-19 45t19 45t45 19h256q33 0 53 -28l267 -400 q91 44 192 44q185 0 316.5 -131.5t131.5 -316.5z" /> <glyph glyph-name="_487" unicode="" d="M384 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1362 716l-72 384q-5 23 -22.5 37.5t-40.5 14.5 h-918q-23 0 -40.5 -14.5t-22.5 -37.5l-72 -384q-5 -30 14 -53t49 -23h1062q30 0 49 23t14 53zM1136 1328q0 20 -14 34t-34 14h-640q-20 0 -34 -14t-14 -34t14 -34t34 -14h640q20 0 34 14t14 34zM1536 603v-603h-128v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5v128h-768v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5v128h-128v603q0 112 25 223l103 454q9 78 97.5 137t230 89t312.5 30t312.5 -30t230 -89t97.5 -137l105 -454q23 -102 23 -223z" /> <glyph glyph-name="_488" unicode="" horiz-adv-x="2048" d="M1463 704q0 -35 -25 -60.5t-61 -25.5h-702q-36 0 -61 25.5t-25 60.5t25 60.5t61 25.5h702q36 0 61 -25.5t25 -60.5zM1677 704q0 86 -23 170h-982q-36 0 -61 25t-25 60q0 36 25 61t61 25h908q-88 143 -235 227t-320 84q-177 0 -327.5 -87.5t-238 -237.5t-87.5 -327 q0 -86 23 -170h982q36 0 61 -25t25 -60q0 -36 -25 -61t-61 -25h-908q88 -143 235.5 -227t320.5 -84q132 0 253 51.5t208 139t139 208t52 253.5zM2048 959q0 -35 -25 -60t-61 -25h-131q17 -85 17 -170q0 -167 -65.5 -319.5t-175.5 -263t-262.5 -176t-319.5 -65.5 q-246 0 -448.5 133t-301.5 350h-189q-36 0 -61 25t-25 61q0 35 25 60t61 25h132q-17 85 -17 170q0 167 65.5 319.5t175.5 263t262.5 176t320.5 65.5q245 0 447.5 -133t301.5 -350h188q36 0 61 -25t25 -61z" /> <glyph glyph-name="_489" unicode="" horiz-adv-x="1280" d="M953 1158l-114 -328l117 -21q165 451 165 518q0 56 -38 56q-57 0 -130 -225zM654 471l33 -88q37 42 71 67l-33 5.5t-38.5 7t-32.5 8.5zM362 1367q0 -98 159 -521q17 10 49 10q15 0 75 -5l-121 351q-75 220 -123 220q-19 0 -29 -17.5t-10 -37.5zM283 608q0 -36 51.5 -119 t117.5 -153t100 -70q14 0 25.5 13t11.5 27q0 24 -32 102q-13 32 -32 72t-47.5 89t-61.5 81t-62 32q-20 0 -45.5 -27t-25.5 -47zM125 273q0 -41 25 -104q59 -145 183.5 -227t281.5 -82q227 0 382 170q152 169 152 427q0 43 -1 67t-11.5 62t-30.5 56q-56 49 -211.5 75.5 t-270.5 26.5q-37 0 -49 -11q-12 -5 -12 -35q0 -34 21.5 -60t55.5 -40t77.5 -23.5t87.5 -11.5t85 -4t70 0h23q24 0 40 -19q15 -19 19 -55q-28 -28 -96 -54q-61 -22 -93 -46q-64 -46 -108.5 -114t-44.5 -137q0 -31 18.5 -88.5t18.5 -87.5l-3 -12q-4 -12 -4 -14 q-137 10 -146 216q-8 -2 -41 -2q2 -7 2 -21q0 -53 -40.5 -89.5t-94.5 -36.5q-82 0 -166.5 78t-84.5 159q0 34 33 67q52 -64 60 -76q77 -104 133 -104q12 0 26.5 8.5t14.5 20.5q0 34 -87.5 145t-116.5 111q-43 0 -70 -44.5t-27 -90.5zM11 264q0 101 42.5 163t136.5 88 q-28 74 -28 104q0 62 61 123t122 61q29 0 70 -15q-163 462 -163 567q0 80 41 130.5t119 50.5q131 0 325 -581q6 -17 8 -23q6 16 29 79.5t43.5 118.5t54 127.5t64.5 123t70.5 86.5t76.5 36q71 0 112 -49t41 -122q0 -108 -159 -550q61 -15 100.5 -46t58.5 -78t26 -93.5 t7 -110.5q0 -150 -47 -280t-132 -225t-211 -150t-278 -55q-111 0 -223 42q-149 57 -258 191.5t-109 286.5z" /> <glyph glyph-name="_490" unicode="" horiz-adv-x="2048" d="M785 528h207q-14 -158 -98.5 -248.5t-214.5 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-203q-5 64 -35.5 99t-81.5 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t40 -51.5t66 -18q95 0 109 139zM1497 528h206 q-14 -158 -98 -248.5t-214 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-204q-4 64 -35 99t-81 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t39.5 -51.5t65.5 -18q49 0 76.5 38t33.5 101zM1856 647q0 207 -15.5 307 t-60.5 161q-6 8 -13.5 14t-21.5 15t-16 11q-86 63 -697 63q-625 0 -710 -63q-5 -4 -17.5 -11.5t-21 -14t-14.5 -14.5q-45 -60 -60 -159.5t-15 -308.5q0 -208 15 -307.5t60 -160.5q6 -8 15 -15t20.5 -14t17.5 -12q44 -33 239.5 -49t470.5 -16q610 0 697 65q5 4 17 11t20.5 14 t13.5 16q46 60 61 159t15 309zM2048 1408v-1536h-2048v1536h2048z" /> <glyph glyph-name="_491" unicode="" d="M992 912v-496q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v496q0 112 -80 192t-192 80h-272v-1152q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v1344q0 14 9 23t23 9h464q135 0 249 -66.5t180.5 -180.5t66.5 -249zM1376 1376v-880q0 -135 -66.5 -249t-180.5 -180.5 t-249 -66.5h-464q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h160q14 0 23 -9t9 -23v-768h272q112 0 192 80t80 192v880q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" /> <glyph glyph-name="_492" unicode="" d="M1311 694v-114q0 -24 -13.5 -38t-37.5 -14h-202q-24 0 -38 14t-14 38v114q0 24 14 38t38 14h202q24 0 37.5 -14t13.5 -38zM821 464v250q0 53 -32.5 85.5t-85.5 32.5h-133q-68 0 -96 -52q-28 52 -96 52h-130q-53 0 -85.5 -32.5t-32.5 -85.5v-250q0 -22 21 -22h55 q22 0 22 22v230q0 24 13.5 38t38.5 14h94q24 0 38 -14t14 -38v-230q0 -22 21 -22h54q22 0 22 22v230q0 24 14 38t38 14h97q24 0 37.5 -14t13.5 -38v-230q0 -22 22 -22h55q21 0 21 22zM1410 560v154q0 53 -33 85.5t-86 32.5h-264q-53 0 -86 -32.5t-33 -85.5v-410 q0 -21 22 -21h55q21 0 21 21v180q31 -42 94 -42h191q53 0 86 32.5t33 85.5zM1536 1176v-1072q0 -96 -68 -164t-164 -68h-1072q-96 0 -164 68t-68 164v1072q0 96 68 164t164 68h1072q96 0 164 -68t68 -164z" /> <glyph glyph-name="_493" unicode="" d="M915 450h-294l147 551zM1001 128h311l-324 1024h-440l-324 -1024h311l383 314zM1536 1120v-960q0 -118 -85 -203t-203 -85h-960q-118 0 -203 85t-85 203v960q0 118 85 203t203 85h960q118 0 203 -85t85 -203z" /> <glyph glyph-name="_494" unicode="" horiz-adv-x="2048" d="M2048 641q0 -21 -13 -36.5t-33 -19.5l-205 -356q3 -9 3 -18q0 -20 -12.5 -35.5t-32.5 -19.5l-193 -337q3 -8 3 -16q0 -23 -16.5 -40t-40.5 -17q-25 0 -41 18h-400q-17 -20 -43 -20t-43 20h-399q-17 -20 -43 -20q-23 0 -40 16.5t-17 40.5q0 8 4 20l-193 335 q-20 4 -32.5 19.5t-12.5 35.5q0 9 3 18l-206 356q-20 5 -32.5 20.5t-12.5 35.5q0 21 13.5 36.5t33.5 19.5l199 344q0 1 -0.5 3t-0.5 3q0 36 34 51l209 363q-4 10 -4 18q0 24 17 40.5t40 16.5q26 0 44 -21h396q16 21 43 21t43 -21h398q18 21 44 21q23 0 40 -16.5t17 -40.5 q0 -6 -4 -18l207 -358q23 -1 39 -17.5t16 -38.5q0 -13 -7 -27l187 -324q19 -4 31.5 -19.5t12.5 -35.5zM1063 -158h389l-342 354h-143l-342 -354h360q18 16 39 16t39 -16zM112 654q1 -4 1 -13q0 -10 -2 -15l208 -360l15 -6l188 199v347l-187 194q-13 -8 -29 -10zM986 1438 h-388l190 -200l554 200h-280q-16 -16 -38 -16t-38 16zM1689 226q1 6 5 11l-64 68l-17 -79h76zM1583 226l22 105l-252 266l-296 -307l63 -64h463zM1495 -142l16 28l65 310h-427l333 -343q8 4 13 5zM578 -158h5l342 354h-373v-335l4 -6q14 -5 22 -13zM552 226h402l64 66 l-309 321l-157 -166v-221zM359 226h163v189l-168 -177q4 -8 5 -12zM358 1051q0 -1 0.5 -2t0.5 -2q0 -16 -8 -29l171 -177v269zM552 1121v-311l153 -157l297 314l-223 236zM556 1425l-4 -8v-264l205 74l-191 201q-6 -2 -10 -3zM1447 1438h-16l-621 -224l213 -225zM1023 946 l-297 -315l311 -319l296 307zM688 634l-136 141v-284zM1038 270l-42 -44h85zM1374 618l238 -251l132 624l-3 5l-1 1zM1718 1018q-8 13 -8 29v2l-216 376q-5 1 -13 5l-437 -463l310 -327zM522 1142v223l-163 -282zM522 196h-163l163 -283v283zM1607 196l-48 -227l130 227h-82 zM1729 266l207 361q-2 10 -2 14q0 1 3 16l-171 296l-129 -612l77 -82q5 3 15 7z" /> <glyph glyph-name="f210" unicode="" d="M0 856q0 131 91.5 226.5t222.5 95.5h742l352 358v-1470q0 -132 -91.5 -227t-222.5 -95h-780q-131 0 -222.5 95t-91.5 227v790zM1232 102l-176 180v425q0 46 -32 79t-78 33h-484q-46 0 -78 -33t-32 -79v-492q0 -46 32.5 -79.5t77.5 -33.5h770z" /> <glyph glyph-name="_496" unicode="" d="M934 1386q-317 -121 -556 -362.5t-358 -560.5q-20 89 -20 176q0 208 102.5 384.5t278.5 279t384 102.5q82 0 169 -19zM1203 1267q93 -65 164 -155q-389 -113 -674.5 -400.5t-396.5 -676.5q-93 72 -155 162q112 386 395 671t667 399zM470 -67q115 356 379.5 622t619.5 384 q40 -92 54 -195q-292 -120 -516 -345t-343 -518q-103 14 -194 52zM1536 -125q-193 50 -367 115q-135 -84 -290 -107q109 205 274 370.5t369 275.5q-21 -152 -101 -284q65 -175 115 -370z" /> <glyph glyph-name="f212" unicode="" horiz-adv-x="2048" d="M1893 1144l155 -1272q-131 0 -257 57q-200 91 -393 91q-226 0 -374 -148q-148 148 -374 148q-193 0 -393 -91q-128 -57 -252 -57h-5l155 1272q224 127 482 127q233 0 387 -106q154 106 387 106q258 0 482 -127zM1398 157q129 0 232 -28.5t260 -93.5l-124 1021 q-171 78 -368 78q-224 0 -374 -141q-150 141 -374 141q-197 0 -368 -78l-124 -1021q105 43 165.5 65t148.5 39.5t178 17.5q202 0 374 -108q172 108 374 108zM1438 191l-55 907q-211 -4 -359 -155q-152 155 -374 155q-176 0 -336 -66l-114 -941q124 51 228.5 76t221.5 25 q209 0 374 -102q172 107 374 102z" /> <glyph glyph-name="_498" unicode="" horiz-adv-x="2048" d="M1500 165v733q0 21 -15 36t-35 15h-93q-20 0 -35 -15t-15 -36v-733q0 -20 15 -35t35 -15h93q20 0 35 15t15 35zM1216 165v531q0 20 -15 35t-35 15h-101q-20 0 -35 -15t-15 -35v-531q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM924 165v429q0 20 -15 35t-35 15h-101 q-20 0 -35 -15t-15 -35v-429q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM632 165v362q0 20 -15 35t-35 15h-101q-20 0 -35 -15t-15 -35v-362q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM2048 311q0 -166 -118 -284t-284 -118h-1244q-166 0 -284 118t-118 284 q0 116 63 214.5t168 148.5q-10 34 -10 73q0 113 80.5 193.5t193.5 80.5q102 0 180 -67q45 183 194 300t338 117q149 0 275 -73.5t199.5 -199.5t73.5 -275q0 -66 -14 -122q135 -33 221 -142.5t86 -247.5z" /> <glyph glyph-name="_499" unicode="" d="M0 1536h1536v-1392l-776 -338l-760 338v1392zM1436 209v926h-1336v-926l661 -294zM1436 1235v201h-1336v-201h1336zM181 937v-115h-37v115h37zM181 789v-115h-37v115h37zM181 641v-115h-37v115h37zM181 493v-115h-37v115h37zM181 345v-115h-37v115h37zM207 202l15 34 l105 -47l-15 -33zM343 142l15 34l105 -46l-15 -34zM478 82l15 34l105 -46l-15 -34zM614 23l15 33l104 -46l-15 -34zM797 10l105 46l15 -33l-105 -47zM932 70l105 46l15 -34l-105 -46zM1068 130l105 46l15 -34l-105 -46zM1203 189l105 47l15 -34l-105 -46zM259 1389v-36h-114 v36h114zM421 1389v-36h-115v36h115zM583 1389v-36h-115v36h115zM744 1389v-36h-114v36h114zM906 1389v-36h-114v36h114zM1068 1389v-36h-115v36h115zM1230 1389v-36h-115v36h115zM1391 1389v-36h-114v36h114zM181 1049v-79h-37v115h115v-36h-78zM421 1085v-36h-115v36h115z M583 1085v-36h-115v36h115zM744 1085v-36h-114v36h114zM906 1085v-36h-114v36h114zM1068 1085v-36h-115v36h115zM1230 1085v-36h-115v36h115zM1355 970v79h-78v36h115v-115h-37zM1355 822v115h37v-115h-37zM1355 674v115h37v-115h-37zM1355 526v115h37v-115h-37zM1355 378 v115h37v-115h-37zM1355 230v115h37v-115h-37zM760 265q-129 0 -221 91.5t-92 221.5q0 129 92 221t221 92q130 0 221.5 -92t91.5 -221q0 -130 -91.5 -221.5t-221.5 -91.5zM595 646q0 -36 19.5 -56.5t49.5 -25t64 -7t64 -2t49.5 -9t19.5 -30.5q0 -49 -112 -49q-97 0 -123 51 h-3l-31 -63q67 -42 162 -42q29 0 56.5 5t55.5 16t45.5 33t17.5 53q0 46 -27.5 69.5t-67.5 27t-79.5 3t-67 5t-27.5 25.5q0 21 20.5 33t40.5 15t41 3q34 0 70.5 -11t51.5 -34h3l30 58q-3 1 -21 8.5t-22.5 9t-19.5 7t-22 7t-20 4.5t-24 4t-23 1q-29 0 -56.5 -5t-54 -16.5 t-43 -34t-16.5 -53.5z" /> <glyph glyph-name="_500" unicode="" horiz-adv-x="2048" d="M863 504q0 112 -79.5 191.5t-191.5 79.5t-191 -79.5t-79 -191.5t79 -191t191 -79t191.5 79t79.5 191zM1726 505q0 112 -79 191t-191 79t-191.5 -79t-79.5 -191q0 -113 79.5 -192t191.5 -79t191 79.5t79 191.5zM2048 1314v-1348q0 -44 -31.5 -75.5t-76.5 -31.5h-1832 q-45 0 -76.5 31.5t-31.5 75.5v1348q0 44 31.5 75.5t76.5 31.5h431q44 0 76 -31.5t32 -75.5v-161h754v161q0 44 32 75.5t76 31.5h431q45 0 76.5 -31.5t31.5 -75.5z" /> <glyph glyph-name="_501" unicode="" horiz-adv-x="2048" d="M1430 953zM1690 749q148 0 253 -98.5t105 -244.5q0 -157 -109 -261.5t-267 -104.5q-85 0 -162 27.5t-138 73.5t-118 106t-109 126t-103.5 132.5t-108.5 126.5t-117 106t-136 73.5t-159 27.5q-154 0 -251.5 -91.5t-97.5 -244.5q0 -157 104 -250t263 -93q100 0 208 37.5 t193 98.5q5 4 21 18.5t30 24t22 9.5q14 0 24.5 -10.5t10.5 -24.5q0 -24 -60 -77q-101 -88 -234.5 -142t-260.5 -54q-133 0 -245.5 58t-180 165t-67.5 241q0 205 141.5 341t347.5 136q120 0 226.5 -43.5t185.5 -113t151.5 -153t139 -167.5t133.5 -153.5t149.5 -113 t172.5 -43.5q102 0 168.5 61.5t66.5 162.5q0 95 -64.5 159t-159.5 64q-30 0 -81.5 -18.5t-68.5 -18.5q-20 0 -35.5 15t-15.5 35q0 18 8.5 57t8.5 59q0 159 -107.5 263t-266.5 104q-58 0 -111.5 -18.5t-84 -40.5t-55.5 -40.5t-33 -18.5q-15 0 -25.5 10.5t-10.5 25.5 q0 19 25 46q59 67 147 103.5t182 36.5q191 0 318 -125.5t127 -315.5q0 -37 -4 -66q57 15 115 15z" /> <glyph glyph-name="_502" unicode="" horiz-adv-x="1664" d="M1216 832q0 26 -19 45t-45 19h-128v128q0 26 -19 45t-45 19t-45 -19t-19 -45v-128h-128q-26 0 -45 -19t-19 -45t19 -45t45 -19h128v-128q0 -26 19 -45t45 -19t45 19t19 45v128h128q26 0 45 19t19 45zM640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920 q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" /> <glyph glyph-name="_503" unicode="" horiz-adv-x="1664" d="M1280 832q0 26 -19 45t-45 19t-45 -19l-147 -146v293q0 26 -19 45t-45 19t-45 -19t-19 -45v-293l-147 146q-19 19 -45 19t-45 -19t-19 -45t19 -45l256 -256q19 -19 45 -19t45 19l256 256q19 19 19 45zM640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920 q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" /> <glyph glyph-name="_504" unicode="" horiz-adv-x="2048" d="M212 768l623 -665l-300 665h-323zM1024 -4l349 772h-698zM538 896l204 384h-262l-288 -384h346zM1213 103l623 665h-323zM683 896h682l-204 384h-274zM1510 896h346l-288 384h-262zM1651 1382l384 -512q14 -18 13 -41.5t-17 -40.5l-960 -1024q-18 -20 -47 -20t-47 20 l-960 1024q-16 17 -17 40.5t13 41.5l384 512q18 26 51 26h1152q33 0 51 -26z" /> <glyph glyph-name="_505" unicode="" horiz-adv-x="2048" d="M1811 -19q19 19 45 19t45 -19l128 -128l-90 -90l-83 83l-83 -83q-18 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83 q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-128 128l90 90l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83 q19 19 45 19t45 -19l83 -83zM237 19q-19 -19 -45 -19t-45 19l-128 128l90 90l83 -82l83 82q19 19 45 19t45 -19l83 -82l64 64v293l-210 314q-17 26 -7 56.5t40 40.5l177 58v299h128v128h256v128h256v-128h256v-128h128v-299l177 -58q30 -10 40 -40.5t-7 -56.5l-210 -314 v-293l19 18q19 19 45 19t45 -19l83 -82l83 82q19 19 45 19t45 -19l128 -128l-90 -90l-83 83l-83 -83q-18 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83 q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83zM640 1152v-128l384 128l384 -128v128h-128v128h-512v-128h-128z" /> <glyph glyph-name="_506" unicode="" d="M576 0l96 448l-96 128l-128 64zM832 0l128 640l-128 -64l-96 -128zM992 1010q-2 4 -4 6q-10 8 -96 8q-70 0 -167 -19q-7 -2 -21 -2t-21 2q-97 19 -167 19q-86 0 -96 -8q-2 -2 -4 -6q2 -18 4 -27q2 -3 7.5 -6.5t7.5 -10.5q2 -4 7.5 -20.5t7 -20.5t7.5 -17t8.5 -17t9 -14 t12 -13.5t14 -9.5t17.5 -8t20.5 -4t24.5 -2q36 0 59 12.5t32.5 30t14.5 34.5t11.5 29.5t17.5 12.5h12q11 0 17.5 -12.5t11.5 -29.5t14.5 -34.5t32.5 -30t59 -12.5q13 0 24.5 2t20.5 4t17.5 8t14 9.5t12 13.5t9 14t8.5 17t7.5 17t7 20.5t7.5 20.5q2 7 7.5 10.5t7.5 6.5 q2 9 4 27zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 61 4.5 118t19 125.5t37.5 123.5t63.5 103.5t93.5 74.5l-90 220h214q-22 64 -22 128q0 12 2 32q-194 40 -194 96q0 57 210 99q17 62 51.5 134t70.5 114q32 37 76 37q30 0 84 -31t84 -31t84 31 t84 31q44 0 76 -37q36 -42 70.5 -114t51.5 -134q210 -42 210 -99q0 -56 -194 -96q7 -81 -20 -160h214l-82 -225q63 -33 107.5 -96.5t65.5 -143.5t29 -151.5t8 -148.5z" /> <glyph glyph-name="_507" unicode="" horiz-adv-x="2304" d="M2301 500q12 -103 -22 -198.5t-99 -163.5t-158.5 -106t-196.5 -31q-161 11 -279.5 125t-134.5 274q-12 111 27.5 210.5t118.5 170.5l-71 107q-96 -80 -151 -194t-55 -244q0 -27 -18.5 -46.5t-45.5 -19.5h-256h-69q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5 t-131.5 316.5t131.5 316.5t316.5 131.5q76 0 152 -27l24 45q-123 110 -304 110h-64q-26 0 -45 19t-19 45t19 45t45 19h128q78 0 145 -13.5t116.5 -38.5t71.5 -39.5t51 -36.5h512h115l-85 128h-222q-30 0 -49 22.5t-14 52.5q4 23 23 38t43 15h253q33 0 53 -28l70 -105 l114 114q19 19 46 19h101q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-179l115 -172q131 63 275 36q143 -26 244 -134.5t118 -253.5zM448 128q115 0 203 72.5t111 183.5h-314q-35 0 -55 31q-18 32 -1 63l147 277q-47 13 -91 13q-132 0 -226 -94t-94 -226t94 -226 t226 -94zM1856 128q132 0 226 94t94 226t-94 226t-226 94q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94z" /> <glyph glyph-name="_508" unicode="" d="M1408 0q0 -63 -61.5 -113.5t-164 -81t-225 -46t-253.5 -15.5t-253.5 15.5t-225 46t-164 81t-61.5 113.5q0 49 33 88.5t91 66.5t118 44.5t131 29.5q26 5 48 -10.5t26 -41.5q5 -26 -10.5 -48t-41.5 -26q-58 -10 -106 -23.5t-76.5 -25.5t-48.5 -23.5t-27.5 -19.5t-8.5 -12 q3 -11 27 -26.5t73 -33t114 -32.5t160.5 -25t201.5 -10t201.5 10t160.5 25t114 33t73 33.5t27 27.5q-1 4 -8.5 11t-27.5 19t-48.5 23.5t-76.5 25t-106 23.5q-26 4 -41.5 26t-10.5 48q4 26 26 41.5t48 10.5q71 -12 131 -29.5t118 -44.5t91 -66.5t33 -88.5zM1024 896v-384 q0 -26 -19 -45t-45 -19h-64v-384q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v384h-64q-26 0 -45 19t-19 45v384q0 53 37.5 90.5t90.5 37.5h384q53 0 90.5 -37.5t37.5 -90.5zM928 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5 t158.5 -65.5t65.5 -158.5z" /> <glyph glyph-name="_509" unicode="" horiz-adv-x="1792" d="M1280 512h305q-5 -6 -10 -10.5t-9 -7.5l-3 -4l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-5 2 -21 20h369q22 0 39.5 13.5t22.5 34.5l70 281l190 -667q6 -20 23 -33t39 -13q21 0 38 13t23 33l146 485l56 -112q18 -35 57 -35zM1792 940q0 -145 -103 -300h-369l-111 221 q-8 17 -25.5 27t-36.5 8q-45 -5 -56 -46l-129 -430l-196 686q-6 20 -23.5 33t-39.5 13t-39 -13.5t-22 -34.5l-116 -464h-423q-103 155 -103 300q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124 t127 -344z" /> <glyph glyph-name="venus" unicode="" horiz-adv-x="1280" d="M1152 960q0 -221 -147.5 -384.5t-364.5 -187.5v-260h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v260q-150 16 -271.5 103t-186 224t-52.5 292 q11 134 80.5 249t182 188t245.5 88q170 19 319 -54t236 -212t87 -306zM128 960q0 -185 131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5z" /> <glyph glyph-name="_511" unicode="" d="M1472 1408q26 0 45 -19t19 -45v-416q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v262l-382 -383q126 -156 126 -359q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123t223.5 45.5 q203 0 359 -126l382 382h-261q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h416zM576 0q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> <glyph glyph-name="_512" unicode="" horiz-adv-x="1280" d="M830 1220q145 -72 233.5 -210.5t88.5 -305.5q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-217 24 -364.5 187.5 t-147.5 384.5q0 167 88.5 305.5t233.5 210.5q-165 96 -228 273q-6 16 3.5 29.5t26.5 13.5h69q21 0 29 -20q44 -106 140 -171t214 -65t214 65t140 171q8 20 37 20h61q17 0 26.5 -13.5t3.5 -29.5q-63 -177 -228 -273zM576 256q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> <glyph glyph-name="_513" unicode="" d="M1024 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q126 -158 126 -359q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64 q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-149 16 -270.5 103t-186.5 223.5t-53 291.5q16 204 160 353.5t347 172.5q118 14 228 -19t198 -103l255 254h-134q-14 0 -23 9t-9 23v64zM576 256q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> <glyph glyph-name="_514" unicode="" horiz-adv-x="1792" d="M1280 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q126 -158 126 -359q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64 q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-217 24 -364.5 187.5t-147.5 384.5q0 201 126 359l-52 53l-101 -111q-9 -10 -22 -10.5t-23 7.5l-48 44q-10 8 -10.5 21.5t8.5 23.5l105 115l-111 112v-134q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9 t-9 23v288q0 26 19 45t45 19h288q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-133l106 -107l86 94q9 10 22 10.5t23 -7.5l48 -44q10 -8 10.5 -21.5t-8.5 -23.5l-90 -99l57 -56q158 126 359 126t359 -126l255 254h-134q-14 0 -23 9t-9 23v64zM832 256q185 0 316.5 131.5 t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> <glyph glyph-name="_515" unicode="" horiz-adv-x="1792" d="M1790 1007q12 -155 -52.5 -292t-186 -224t-271.5 -103v-260h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-512v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23 t23 9h224v260q-150 16 -271.5 103t-186 224t-52.5 292q17 206 164.5 356.5t352.5 169.5q206 21 377 -94q171 115 377 94q205 -19 352.5 -169.5t164.5 -356.5zM896 647q128 131 128 313t-128 313q-128 -131 -128 -313t128 -313zM576 512q115 0 218 57q-154 165 -154 391 q0 224 154 391q-103 57 -218 57q-185 0 -316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5zM1152 128v260q-137 15 -256 94q-119 -79 -256 -94v-260h512zM1216 512q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5q-115 0 -218 -57q154 -167 154 -391 q0 -226 -154 -391q103 -57 218 -57z" /> <glyph glyph-name="_516" unicode="" horiz-adv-x="1920" d="M1536 1120q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q76 -95 107.5 -214t9.5 -247q-31 -182 -166 -312t-318 -156q-210 -29 -384.5 80t-241.5 300q-117 6 -221 57.5t-177.5 133t-113.5 192.5t-32 230 q9 135 78 252t182 191.5t248 89.5q118 14 227.5 -19t198.5 -103l255 254h-134q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q59 -74 93 -169q182 -9 328 -124l255 254h-134q-14 0 -23 9 t-9 23v64zM1024 704q0 20 -4 58q-162 -25 -271 -150t-109 -292q0 -20 4 -58q162 25 271 150t109 292zM128 704q0 -168 111 -294t276 -149q-3 29 -3 59q0 210 135 369.5t338 196.5q-53 120 -163.5 193t-245.5 73q-185 0 -316.5 -131.5t-131.5 -316.5zM1088 -128 q185 0 316.5 131.5t131.5 316.5q0 168 -111 294t-276 149q3 -28 3 -59q0 -210 -135 -369.5t-338 -196.5q53 -120 163.5 -193t245.5 -73z" /> <glyph glyph-name="_517" unicode="" horiz-adv-x="2048" d="M1664 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q76 -95 107.5 -214t9.5 -247q-32 -180 -164.5 -310t-313.5 -157q-223 -34 -409 90q-117 -78 -256 -93v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23 t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-155 17 -279.5 109.5t-187 237.5t-39.5 307q25 187 159.5 322.5t320.5 164.5q224 34 410 -90q146 97 320 97q201 0 359 -126l255 254h-134q-14 0 -23 9 t-9 23v64zM896 391q128 131 128 313t-128 313q-128 -131 -128 -313t128 -313zM128 704q0 -185 131.5 -316.5t316.5 -131.5q117 0 218 57q-154 167 -154 391t154 391q-101 57 -218 57q-185 0 -316.5 -131.5t-131.5 -316.5zM1216 256q185 0 316.5 131.5t131.5 316.5 t-131.5 316.5t-316.5 131.5q-117 0 -218 -57q154 -167 154 -391t-154 -391q101 -57 218 -57z" /> <glyph glyph-name="_518" unicode="" d="M1472 1408q26 0 45 -19t19 -45v-416q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v262l-213 -214l140 -140q9 -10 9 -23t-9 -22l-46 -46q-9 -9 -22 -9t-23 9l-140 141l-78 -79q126 -156 126 -359q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5 t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123t223.5 45.5q203 0 359 -126l78 78l-172 172q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l172 -172l213 213h-261q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h416zM576 0q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> <glyph glyph-name="_519" unicode="" horiz-adv-x="1280" d="M640 892q217 -24 364.5 -187.5t147.5 -384.5q0 -167 -87 -306t-236 -212t-319 -54q-133 15 -245.5 88t-182 188t-80.5 249q-12 155 52.5 292t186 224t271.5 103v132h-160q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h160v165l-92 -92q-10 -9 -23 -9t-22 9l-46 46q-9 9 -9 22 t9 23l202 201q19 19 45 19t45 -19l202 -201q9 -10 9 -23t-9 -22l-46 -46q-9 -9 -22 -9t-23 9l-92 92v-165h160q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-160v-132zM576 -128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5 t131.5 -316.5t316.5 -131.5z" /> <glyph glyph-name="_520" unicode="" horiz-adv-x="2048" d="M1901 621q19 -19 19 -45t-19 -45l-294 -294q-9 -10 -22.5 -10t-22.5 10l-45 45q-10 9 -10 22.5t10 22.5l185 185h-294v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-132q-24 -217 -187.5 -364.5t-384.5 -147.5q-167 0 -306 87t-212 236t-54 319q15 133 88 245.5 t188 182t249 80.5q155 12 292 -52.5t224 -186t103 -271.5h132v224q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-224h294l-185 185q-10 9 -10 22.5t10 22.5l45 45q9 10 22.5 10t22.5 -10zM576 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5 t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> <glyph glyph-name="_521" unicode="" horiz-adv-x="1280" d="M1152 960q0 -221 -147.5 -384.5t-364.5 -187.5v-612q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v612q-217 24 -364.5 187.5t-147.5 384.5q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5zM576 512q185 0 316.5 131.5 t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> <glyph glyph-name="_522" unicode="" horiz-adv-x="1280" d="M1024 576q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1152 576q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123 t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5z" /> <glyph glyph-name="_523" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="_524" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="_525" unicode="" d="M1451 1408q35 0 60 -25t25 -60v-1366q0 -35 -25 -60t-60 -25h-391v595h199l30 232h-229v148q0 56 23.5 84t91.5 28l122 1v207q-63 9 -178 9q-136 0 -217.5 -80t-81.5 -226v-171h-200v-232h200v-595h-735q-35 0 -60 25t-25 60v1366q0 35 25 60t60 25h1366z" /> <glyph glyph-name="_526" unicode="" horiz-adv-x="1280" d="M0 939q0 108 37.5 203.5t103.5 166.5t152 123t185 78t202 26q158 0 294 -66.5t221 -193.5t85 -287q0 -96 -19 -188t-60 -177t-100 -149.5t-145 -103t-189 -38.5q-68 0 -135 32t-96 88q-10 -39 -28 -112.5t-23.5 -95t-20.5 -71t-26 -71t-32 -62.5t-46 -77.5t-62 -86.5 l-14 -5l-9 10q-15 157 -15 188q0 92 21.5 206.5t66.5 287.5t52 203q-32 65 -32 169q0 83 52 156t132 73q61 0 95 -40.5t34 -102.5q0 -66 -44 -191t-44 -187q0 -63 45 -104.5t109 -41.5q55 0 102 25t78.5 68t56 95t38 110.5t20 111t6.5 99.5q0 173 -109.5 269.5t-285.5 96.5 q-200 0 -334 -129.5t-134 -328.5q0 -44 12.5 -85t27 -65t27 -45.5t12.5 -30.5q0 -28 -15 -73t-37 -45q-2 0 -17 3q-51 15 -90.5 56t-61 94.5t-32.5 108t-11 106.5z" /> <glyph glyph-name="_527" unicode="" d="M985 562q13 0 97.5 -44t89.5 -53q2 -5 2 -15q0 -33 -17 -76q-16 -39 -71 -65.5t-102 -26.5q-57 0 -190 62q-98 45 -170 118t-148 185q-72 107 -71 194v8q3 91 74 158q24 22 52 22q6 0 18 -1.5t19 -1.5q19 0 26.5 -6.5t15.5 -27.5q8 -20 33 -88t25 -75q0 -21 -34.5 -57.5 t-34.5 -46.5q0 -7 5 -15q34 -73 102 -137q56 -53 151 -101q12 -7 22 -7q15 0 54 48.5t52 48.5zM782 32q127 0 243.5 50t200.5 134t134 200.5t50 243.5t-50 243.5t-134 200.5t-200.5 134t-243.5 50t-243.5 -50t-200.5 -134t-134 -200.5t-50 -243.5q0 -203 120 -368l-79 -233 l242 77q158 -104 345 -104zM782 1414q153 0 292.5 -60t240.5 -161t161 -240.5t60 -292.5t-60 -292.5t-161 -240.5t-240.5 -161t-292.5 -60q-195 0 -365 94l-417 -134l136 405q-108 178 -108 389q0 153 60 292.5t161 240.5t240.5 161t292.5 60z" /> <glyph glyph-name="_528" unicode="" horiz-adv-x="1792" d="M128 128h1024v128h-1024v-128zM128 640h1024v128h-1024v-128zM1696 192q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM128 1152h1024v128h-1024v-128zM1696 704q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1696 1216 q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1792 384v-384h-1792v384h1792zM1792 896v-384h-1792v384h1792zM1792 1408v-384h-1792v384h1792z" /> <glyph glyph-name="_529" unicode="" horiz-adv-x="2048" d="M704 640q-159 0 -271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5zM1664 512h352q13 0 22.5 -9.5t9.5 -22.5v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-352q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5 t-9.5 22.5v352h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v352q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5v-352zM928 288q0 -52 38 -90t90 -38h256v-238q-68 -50 -171 -50h-874q-121 0 -194 69t-73 190q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q19 0 39 -17q79 -61 154.5 -91.5t164.5 -30.5t164.5 30.5t154.5 91.5q20 17 39 17q132 0 217 -96h-223q-52 0 -90 -38t-38 -90v-192z" /> <glyph glyph-name="_530" unicode="" horiz-adv-x="2048" d="M704 640q-159 0 -271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5zM1781 320l249 -249q9 -9 9 -23q0 -13 -9 -22l-136 -136q-9 -9 -22 -9q-14 0 -23 9l-249 249l-249 -249q-9 -9 -23 -9q-13 0 -22 9l-136 136 q-9 9 -9 22q0 14 9 23l249 249l-249 249q-9 9 -9 23q0 13 9 22l136 136q9 9 22 9q14 0 23 -9l249 -249l249 249q9 9 23 9q13 0 22 -9l136 -136q9 -9 9 -22q0 -14 -9 -23zM1283 320l-181 -181q-37 -37 -37 -91q0 -53 37 -90l83 -83q-21 -3 -44 -3h-874q-121 0 -194 69 t-73 190q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q19 0 39 -17q154 -122 319 -122t319 122q20 17 39 17q28 0 57 -6q-28 -27 -41 -50t-13 -56q0 -54 37 -91z" /> <glyph glyph-name="_531" unicode="" horiz-adv-x="2048" d="M256 512h1728q26 0 45 -19t19 -45v-448h-256v256h-1536v-256h-256v1216q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-704zM832 832q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM2048 576v64q0 159 -112.5 271.5t-271.5 112.5h-704 q-26 0 -45 -19t-19 -45v-384h1152z" /> <glyph glyph-name="_532" unicode="" d="M1536 1536l-192 -448h192v-192h-274l-55 -128h329v-192h-411l-357 -832l-357 832h-411v192h329l-55 128h-274v192h192l-192 448h256l323 -768h378l323 768h256zM768 320l108 256h-216z" /> <glyph glyph-name="_533" unicode="" d="M1088 1536q185 0 316.5 -93.5t131.5 -226.5v-896q0 -130 -125.5 -222t-305.5 -97l213 -202q16 -15 8 -35t-30 -20h-1056q-22 0 -30 20t8 35l213 202q-180 5 -305.5 97t-125.5 222v896q0 133 131.5 226.5t316.5 93.5h640zM768 192q80 0 136 56t56 136t-56 136t-136 56 t-136 -56t-56 -136t56 -136t136 -56zM1344 768v512h-1152v-512h1152z" /> <glyph glyph-name="_534" unicode="" d="M1088 1536q185 0 316.5 -93.5t131.5 -226.5v-896q0 -130 -125.5 -222t-305.5 -97l213 -202q16 -15 8 -35t-30 -20h-1056q-22 0 -30 20t8 35l213 202q-180 5 -305.5 97t-125.5 222v896q0 133 131.5 226.5t316.5 93.5h640zM288 224q66 0 113 47t47 113t-47 113t-113 47 t-113 -47t-47 -113t47 -113t113 -47zM704 768v512h-544v-512h544zM1248 224q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM1408 768v512h-576v-512h576z" /> <glyph glyph-name="_535" unicode="" horiz-adv-x="1792" d="M597 1115v-1173q0 -25 -12.5 -42.5t-36.5 -17.5q-17 0 -33 8l-465 233q-21 10 -35.5 33.5t-14.5 46.5v1140q0 20 10 34t29 14q14 0 44 -15l511 -256q3 -3 3 -5zM661 1014l534 -866l-534 266v600zM1792 996v-1054q0 -25 -14 -40.5t-38 -15.5t-47 13l-441 220zM1789 1116 q0 -3 -256.5 -419.5t-300.5 -487.5l-390 634l324 527q17 28 52 28q14 0 26 -6l541 -270q4 -2 4 -6z" /> <glyph glyph-name="_536" unicode="" d="M809 532l266 499h-112l-157 -312q-24 -48 -44 -92l-42 92l-155 312h-120l263 -493v-324h101v318zM1536 1408v-1536h-1536v1536h1536z" /> <glyph glyph-name="_537" unicode="" horiz-adv-x="2296" d="M478 -139q-8 -16 -27 -34.5t-37 -25.5q-25 -9 -51.5 3.5t-28.5 31.5q-1 22 40 55t68 38q23 4 34 -21.5t2 -46.5zM1819 -139q7 -16 26 -34.5t38 -25.5q25 -9 51.5 3.5t27.5 31.5q2 22 -39.5 55t-68.5 38q-22 4 -33 -21.5t-2 -46.5zM1867 -30q13 -27 56.5 -59.5t77.5 -41.5 q45 -13 82 4.5t37 50.5q0 46 -67.5 100.5t-115.5 59.5q-40 5 -63.5 -37.5t-6.5 -76.5zM428 -30q-13 -27 -56 -59.5t-77 -41.5q-45 -13 -82 4.5t-37 50.5q0 46 67.5 100.5t115.5 59.5q40 5 63 -37.5t6 -76.5zM1158 1094h1q-41 0 -76 -15q27 -8 44 -30.5t17 -49.5 q0 -35 -27 -60t-65 -25q-52 0 -80 43q-5 -23 -5 -42q0 -74 56 -126.5t135 -52.5q80 0 136 52.5t56 126.5t-56 126.5t-136 52.5zM1462 1312q-99 109 -220.5 131.5t-245.5 -44.5q27 60 82.5 96.5t118 39.5t121.5 -17t99.5 -74.5t44.5 -131.5zM2212 73q8 -11 -11 -42 q7 -23 7 -40q1 -56 -44.5 -112.5t-109.5 -91.5t-118 -37q-48 -2 -92 21.5t-66 65.5q-687 -25 -1259 0q-23 -41 -66.5 -65t-92.5 -22q-86 3 -179.5 80.5t-92.5 160.5q2 22 7 40q-19 31 -11 42q6 10 31 1q14 22 41 51q-7 29 2 38q11 10 39 -4q29 20 59 34q0 29 13 37 q23 12 51 -16q35 5 61 -2q18 -4 38 -19v73q-11 0 -18 2q-53 10 -97 44.5t-55 87.5q-9 38 0 81q15 62 93 95q2 17 19 35.5t36 23.5t33 -7.5t19 -30.5h13q46 -5 60 -23q3 -3 5 -7q10 1 30.5 3.5t30.5 3.5q-15 11 -30 17q-23 40 -91 43q0 6 1 10q-62 2 -118.5 18.5t-84.5 47.5 q-32 36 -42.5 92t-2.5 112q16 126 90 179q23 16 52 4.5t32 -40.5q0 -1 1.5 -14t2.5 -21t3 -20t5.5 -19t8.5 -10q27 -14 76 -12q48 46 98 74q-40 4 -162 -14l47 46q61 58 163 111q145 73 282 86q-20 8 -41 15.5t-47 14t-42.5 10.5t-47.5 11t-43 10q595 126 904 -139 q98 -84 158 -222q85 -10 121 9h1q5 3 8.5 10t5.5 19t3 19.5t3 21.5l1 14q3 28 32 40t52 -5q73 -52 91 -178q7 -57 -3.5 -113t-42.5 -91q-28 -32 -83.5 -48.5t-115.5 -18.5v-10q-71 -2 -95 -43q-14 -5 -31 -17q11 -1 32 -3.5t30 -3.5q1 5 5 8q16 18 60 23h13q5 18 19 30t33 8 t36 -23t19 -36q79 -32 93 -95q9 -40 1 -81q-12 -53 -56 -88t-97 -44q-10 -2 -17 -2q0 -49 -1 -73q20 15 38 19q26 7 61 2q28 28 51 16q14 -9 14 -37q33 -16 59 -34q27 13 38 4q10 -10 2 -38q28 -30 41 -51q23 8 31 -1zM1937 1025q0 -29 -9 -54q82 -32 112 -132 q4 37 -9.5 98.5t-41.5 90.5q-20 19 -36 17t-16 -20zM1859 925q35 -42 47.5 -108.5t-0.5 -124.5q67 13 97 45q13 14 18 28q-3 64 -31 114.5t-79 66.5q-15 -15 -52 -21zM1822 921q-30 0 -44 1q42 -115 53 -239q21 0 43 3q16 68 1 135t-53 100zM258 839q30 100 112 132 q-9 25 -9 54q0 18 -16.5 20t-35.5 -17q-28 -29 -41.5 -90.5t-9.5 -98.5zM294 737q29 -31 97 -45q-13 58 -0.5 124.5t47.5 108.5v0q-37 6 -52 21q-51 -16 -78.5 -66t-31.5 -115q9 -17 18 -28zM471 683q14 124 73 235q-19 -4 -55 -18l-45 -19v1q-46 -89 -20 -196q25 -3 47 -3z M1434 644q8 -38 16.5 -108.5t11.5 -89.5q3 -18 9.5 -21.5t23.5 4.5q40 20 62 85.5t23 125.5q-24 2 -146 4zM1152 1285q-116 0 -199 -82.5t-83 -198.5q0 -117 83 -199.5t199 -82.5t199 82.5t83 199.5q0 116 -83 198.5t-199 82.5zM1380 646q-105 2 -211 0v1q-1 -27 2.5 -86 t13.5 -66q29 -14 93.5 -14.5t95.5 10.5q9 3 11 39t-0.5 69.5t-4.5 46.5zM1112 447q8 4 9.5 48t-0.5 88t-4 63v1q-212 -3 -214 -3q-4 -20 -7 -62t0 -83t14 -46q34 -15 101 -16t101 10zM718 636q-16 -59 4.5 -118.5t77.5 -84.5q15 -8 24 -5t12 21q3 16 8 90t10 103 q-69 -2 -136 -6zM591 510q3 -23 -34 -36q132 -141 271.5 -240t305.5 -154q172 49 310.5 146t293.5 250q-33 13 -30 34q0 2 0.5 3.5t1.5 3t1 2.5v1v-1q-17 2 -50 5.5t-48 4.5q-26 -90 -82 -132q-51 -38 -82 1q-5 6 -9 14q-7 13 -17 62q-2 -5 -5 -9t-7.5 -7t-8 -5.5t-9.5 -4 l-10 -2.5t-12 -2l-12 -1.5t-13.5 -1t-13.5 -0.5q-106 -9 -163 11q-4 -17 -10 -26.5t-21 -15t-23 -7t-36 -3.5q-6 -1 -9 -1q-179 -17 -203 40q-2 -63 -56 -54q-47 8 -91 54q-12 13 -20 26q-17 29 -26 65q-58 -6 -87 -10q1 -2 4 -10zM507 -118q3 14 3 30q-17 71 -51 130 t-73 70q-41 12 -101.5 -14.5t-104.5 -80t-39 -107.5q35 -53 100 -93t119 -42q51 -2 94 28t53 79zM510 53q23 -63 27 -119q195 113 392 174q-98 52 -180.5 120t-179.5 165q-6 -4 -29 -13q0 -1 -1 -4t-1 -5q31 -18 22 -37q-12 -23 -56 -34q-10 -13 -29 -24h-1q-2 -83 1 -150 q19 -34 35 -73zM579 -113q532 -21 1145 0q-254 147 -428 196q-76 -35 -156 -57q-8 -3 -16 0q-65 21 -129 49q-208 -60 -416 -188h-1v-1q1 0 1 1zM1763 -67q4 54 28 120q14 38 33 71l-1 -1q3 77 3 153q-15 8 -30 25q-42 9 -56 33q-9 20 22 38q-2 4 -2 9q-16 4 -28 12 q-204 -190 -383 -284q198 -59 414 -176zM2155 -90q5 54 -39 107.5t-104 80t-102 14.5q-38 -11 -72.5 -70.5t-51.5 -129.5q0 -16 3 -30q10 -49 53 -79t94 -28q54 2 119 42t100 93z" /> <glyph glyph-name="_538" unicode="" horiz-adv-x="2304" d="M1524 -25q0 -68 -48 -116t-116 -48t-116.5 48t-48.5 116t48.5 116.5t116.5 48.5t116 -48.5t48 -116.5zM775 -25q0 -68 -48.5 -116t-116.5 -48t-116 48t-48 116t48 116.5t116 48.5t116.5 -48.5t48.5 -116.5zM0 1469q57 -60 110.5 -104.5t121 -82t136 -63t166 -45.5 t200 -31.5t250 -18.5t304 -9.5t372.5 -2.5q139 0 244.5 -5t181 -16.5t124 -27.5t71 -39.5t24 -51.5t-19.5 -64t-56.5 -76.5t-89.5 -91t-116 -104.5t-139 -119q-185 -157 -286 -247q29 51 76.5 109t94 105.5t94.5 98.5t83 91.5t54 80.5t13 70t-45.5 55.5t-116.5 41t-204 23.5 t-304 5q-168 -2 -314 6t-256 23t-204.5 41t-159.5 51.5t-122.5 62.5t-91.5 66.5t-68 71.5t-50.5 69.5t-40 68t-36.5 59.5z" /> <glyph glyph-name="_539" unicode="" horiz-adv-x="1792" d="M896 1472q-169 0 -323 -66t-265.5 -177.5t-177.5 -265.5t-66 -323t66 -323t177.5 -265.5t265.5 -177.5t323 -66t323 66t265.5 177.5t177.5 265.5t66 323t-66 323t-177.5 265.5t-265.5 177.5t-323 66zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348 t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM496 704q16 0 16 -16v-480q0 -16 -16 -16h-32q-16 0 -16 16v480q0 16 16 16h32zM896 640q53 0 90.5 -37.5t37.5 -90.5q0 -35 -17.5 -64t-46.5 -46v-114q0 -14 -9 -23 t-23 -9h-64q-14 0 -23 9t-9 23v114q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5zM896 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM544 928v-96 q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v96q0 93 65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5v-96q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v96q0 146 -103 249t-249 103t-249 -103t-103 -249zM1408 192v512q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-512 q0 -26 19 -45t45 -19h896q26 0 45 19t19 45z" /> <glyph glyph-name="_540" unicode="" horiz-adv-x="2304" d="M1920 1024v-768h-1664v768h1664zM2048 448h128v384h-128v288q0 14 -9 23t-23 9h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288zM2304 832v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113 v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160q53 0 90.5 -37.5t37.5 -90.5z" /> <glyph glyph-name="_541" unicode="" horiz-adv-x="2304" d="M256 256v768h1280v-768h-1280zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9 h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" /> <glyph glyph-name="_542" unicode="" horiz-adv-x="2304" d="M256 256v768h896v-768h-896zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9 h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" /> <glyph glyph-name="_543" unicode="" horiz-adv-x="2304" d="M256 256v768h512v-768h-512zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9 h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" /> <glyph glyph-name="_544" unicode="" horiz-adv-x="2304" d="M2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9h-1856q-14 0 -23 -9t-9 -23 v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" /> <glyph glyph-name="_545" unicode="" horiz-adv-x="1280" d="M1133 493q31 -30 14 -69q-17 -40 -59 -40h-382l201 -476q10 -25 0 -49t-34 -35l-177 -75q-25 -10 -49 0t-35 34l-191 452l-312 -312q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v1504q0 42 40 59q12 5 24 5q27 0 45 -19z" /> <glyph glyph-name="_546" unicode="" horiz-adv-x="1024" d="M832 1408q-320 0 -320 -224v-416h128v-128h-128v-544q0 -224 320 -224h64v-128h-64q-272 0 -384 146q-112 -146 -384 -146h-64v128h64q320 0 320 224v544h-128v128h128v416q0 224 -320 224h-64v128h64q272 0 384 -146q112 146 384 146h64v-128h-64z" /> <glyph glyph-name="_547" unicode="" horiz-adv-x="2048" d="M2048 1152h-128v-1024h128v-384h-384v128h-1280v-128h-384v384h128v1024h-128v384h384v-128h1280v128h384v-384zM1792 1408v-128h128v128h-128zM128 1408v-128h128v128h-128zM256 -128v128h-128v-128h128zM1664 0v128h128v1024h-128v128h-1280v-128h-128v-1024h128v-128 h1280zM1920 -128v128h-128v-128h128zM1280 896h384v-768h-896v256h-384v768h896v-256zM512 512h640v512h-640v-512zM1536 256v512h-256v-384h-384v-128h640z" /> <glyph glyph-name="_548" unicode="" horiz-adv-x="2304" d="M2304 768h-128v-640h128v-384h-384v128h-896v-128h-384v384h128v128h-384v-128h-384v384h128v640h-128v384h384v-128h896v128h384v-384h-128v-128h384v128h384v-384zM2048 1024v-128h128v128h-128zM1408 1408v-128h128v128h-128zM128 1408v-128h128v128h-128zM256 256 v128h-128v-128h128zM1536 384h-128v-128h128v128zM384 384h896v128h128v640h-128v128h-896v-128h-128v-640h128v-128zM896 -128v128h-128v-128h128zM2176 -128v128h-128v-128h128zM2048 128v640h-128v128h-384v-384h128v-384h-384v128h-384v-128h128v-128h896v128h128z" /> <glyph glyph-name="_549" unicode="" d="M1024 288v-416h-928q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1344q40 0 68 -28t28 -68v-928h-416q-40 0 -68 -28t-28 -68zM1152 256h381q-15 -82 -65 -132l-184 -184q-50 -50 -132 -65v381z" /> <glyph glyph-name="_550" unicode="" d="M1400 256h-248v-248q29 10 41 22l185 185q12 12 22 41zM1120 384h288v896h-1280v-1280h896v288q0 40 28 68t68 28zM1536 1312v-1024q0 -40 -20 -88t-48 -76l-184 -184q-28 -28 -76 -48t-88 -20h-1024q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1344q40 0 68 -28t28 -68 z" /> <glyph glyph-name="_551" unicode="" horiz-adv-x="2304" d="M1951 538q0 -26 -15.5 -44.5t-38.5 -23.5q-8 -2 -18 -2h-153v140h153q10 0 18 -2q23 -5 38.5 -23.5t15.5 -44.5zM1933 751q0 -25 -15 -42t-38 -21q-3 -1 -15 -1h-139v129h139q3 0 8.5 -0.5t6.5 -0.5q23 -4 38 -21.5t15 -42.5zM728 587v308h-228v-308q0 -58 -38 -94.5 t-105 -36.5q-108 0 -229 59v-112q53 -15 121 -23t109 -9l42 -1q328 0 328 217zM1442 403v113q-99 -52 -200 -59q-108 -8 -169 41t-61 142t61 142t169 41q101 -7 200 -58v112q-48 12 -100 19.5t-80 9.5l-28 2q-127 6 -218.5 -14t-140.5 -60t-71 -88t-22 -106t22 -106t71 -88 t140.5 -60t218.5 -14q101 4 208 31zM2176 518q0 54 -43 88.5t-109 39.5v3q57 8 89 41.5t32 79.5q0 55 -41 88t-107 36q-3 0 -12 0.5t-14 0.5h-455v-510h491q74 0 121.5 36.5t47.5 96.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90 t90 38h2048q52 0 90 -38t38 -90z" /> <glyph glyph-name="_552" unicode="" horiz-adv-x="2304" d="M858 295v693q-106 -41 -172 -135.5t-66 -211.5t66 -211.5t172 -134.5zM1362 641q0 117 -66 211.5t-172 135.5v-694q106 41 172 135.5t66 211.5zM1577 641q0 -159 -78.5 -294t-213.5 -213.5t-294 -78.5q-119 0 -227.5 46.5t-187 125t-125 187t-46.5 227.5q0 159 78.5 294 t213.5 213.5t294 78.5t294 -78.5t213.5 -213.5t78.5 -294zM1960 634q0 139 -55.5 261.5t-147.5 205.5t-213.5 131t-252.5 48h-301q-176 0 -323.5 -81t-235 -230t-87.5 -335q0 -171 87 -317.5t236 -231.5t323 -85h301q129 0 251.5 50.5t214.5 135t147.5 202.5t55.5 246z M2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" /> <glyph glyph-name="_553" unicode="" horiz-adv-x="1792" d="M1664 -96v1088q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5v-1088q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5zM1792 992v-1088q0 -66 -47 -113t-113 -47h-1088q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1088q66 0 113 -47t47 -113 zM1408 1376v-160h-128v160q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5v-1088q0 -13 9.5 -22.5t22.5 -9.5h160v-128h-160q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1088q66 0 113 -47t47 -113z" /> <glyph glyph-name="_554" unicode="" horiz-adv-x="2304" d="M1728 1088l-384 -704h768zM448 1088l-384 -704h768zM1269 1280q-14 -40 -45.5 -71.5t-71.5 -45.5v-1291h608q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1344q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h608v1291q-40 14 -71.5 45.5t-45.5 71.5h-491q-14 0 -23 9t-9 23v64 q0 14 9 23t23 9h491q21 57 70 92.5t111 35.5t111 -35.5t70 -92.5h491q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-491zM1088 1264q33 0 56.5 23.5t23.5 56.5t-23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5zM2176 384q0 -73 -46.5 -131t-117.5 -91 t-144.5 -49.5t-139.5 -16.5t-139.5 16.5t-144.5 49.5t-117.5 91t-46.5 131q0 11 35 81t92 174.5t107 195.5t102 184t56 100q18 33 56 33t56 -33q4 -7 56 -100t102 -184t107 -195.5t92 -174.5t35 -81zM896 384q0 -73 -46.5 -131t-117.5 -91t-144.5 -49.5t-139.5 -16.5 t-139.5 16.5t-144.5 49.5t-117.5 91t-46.5 131q0 11 35 81t92 174.5t107 195.5t102 184t56 100q18 33 56 33t56 -33q4 -7 56 -100t102 -184t107 -195.5t92 -174.5t35 -81z" /> <glyph glyph-name="_555" unicode="" d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM874 700q77 29 149 92.5t129.5 152.5t92.5 210t35 253h-1024q0 -132 35 -253t92.5 -210t129.5 -152.5t149 -92.5q19 -7 30.5 -23.5t11.5 -36.5t-11.5 -36.5t-30.5 -23.5q-77 -29 -149 -92.5 t-129.5 -152.5t-92.5 -210t-35 -253h1024q0 132 -35 253t-92.5 210t-129.5 152.5t-149 92.5q-19 7 -30.5 23.5t-11.5 36.5t11.5 36.5t30.5 23.5z" /> <glyph glyph-name="_556" unicode="" d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM1280 1408h-1024q0 -66 9 -128h1006q9 61 9 128zM1280 -128q0 130 -34 249.5t-90.5 208t-126.5 152t-146 94.5h-230q-76 -31 -146 -94.5t-126.5 -152t-90.5 -208t-34 -249.5h1024z" /> <glyph glyph-name="_557" unicode="" d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM1280 1408h-1024q0 -206 85 -384h854q85 178 85 384zM1223 192q-54 141 -145.5 241.5t-194.5 142.5h-230q-103 -42 -194.5 -142.5t-145.5 -241.5h910z" /> <glyph glyph-name="_558" unicode="" d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM874 700q77 29 149 92.5t129.5 152.5t92.5 210t35 253h-1024q0 -132 35 -253t92.5 -210t129.5 -152.5t149 -92.5q19 -7 30.5 -23.5t11.5 -36.5t-11.5 -36.5t-30.5 -23.5q-137 -51 -244 -196 h700q-107 145 -244 196q-19 7 -30.5 23.5t-11.5 36.5t11.5 36.5t30.5 23.5z" /> <glyph glyph-name="_559" unicode="" d="M1504 -64q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v128q0 14 9 23t23 9h1472zM130 0q3 55 16 107t30 95t46 87t53.5 76t64.5 69.5t66 60t70.5 55t66.5 47.5t65 43q-43 28 -65 43t-66.5 47.5t-70.5 55t-66 60t-64.5 69.5t-53.5 76t-46 87 t-30 95t-16 107h1276q-3 -55 -16 -107t-30 -95t-46 -87t-53.5 -76t-64.5 -69.5t-66 -60t-70.5 -55t-66.5 -47.5t-65 -43q43 -28 65 -43t66.5 -47.5t70.5 -55t66 -60t64.5 -69.5t53.5 -76t46 -87t30 -95t16 -107h-1276zM1504 1536q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9 h-1472q-14 0 -23 9t-9 23v128q0 14 9 23t23 9h1472z" /> <glyph glyph-name="_560" unicode="" d="M768 1152q-53 0 -90.5 -37.5t-37.5 -90.5v-128h-32v93q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-429l-32 30v172q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-224q0 -47 35 -82l310 -296q39 -39 39 -102q0 -26 19 -45t45 -19h640q26 0 45 19t19 45v25 q0 41 10 77l108 436q10 36 10 77v246q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-32h-32v125q0 40 -25 72.5t-64 40.5q-14 2 -23 2q-46 0 -79 -33t-33 -79v-128h-32v122q0 51 -32.5 89.5t-82.5 43.5q-5 1 -13 1zM768 1280q84 0 149 -50q57 34 123 34q59 0 111 -27 t86 -76q27 7 59 7q100 0 170 -71.5t70 -171.5v-246q0 -51 -13 -108l-109 -436q-6 -24 -6 -71q0 -80 -56 -136t-136 -56h-640q-84 0 -138 58.5t-54 142.5l-308 296q-76 73 -76 175v224q0 99 70.5 169.5t169.5 70.5q11 0 16 -1q6 95 75.5 160t164.5 65q52 0 98 -21 q72 69 174 69z" /> <glyph glyph-name="_561" unicode="" horiz-adv-x="1792" d="M880 1408q-46 0 -79 -33t-33 -79v-656h-32v528q0 46 -33 79t-79 33t-79 -33t-33 -79v-528v-256l-154 205q-38 51 -102 51q-53 0 -90.5 -37.5t-37.5 -90.5q0 -43 26 -77l384 -512q38 -51 102 -51h688q34 0 61 22t34 56l76 405q5 32 5 59v498q0 46 -33 79t-79 33t-79 -33 t-33 -79v-272h-32v528q0 46 -33 79t-79 33t-79 -33t-33 -79v-528h-32v656q0 46 -33 79t-79 33zM880 1536q68 0 125.5 -35.5t88.5 -96.5q19 4 42 4q99 0 169.5 -70.5t70.5 -169.5v-17q105 6 180.5 -64t75.5 -175v-498q0 -40 -8 -83l-76 -404q-14 -79 -76.5 -131t-143.5 -52 h-688q-60 0 -114.5 27.5t-90.5 74.5l-384 512q-51 68 -51 154q0 106 75 181t181 75q78 0 128 -34v434q0 99 70.5 169.5t169.5 70.5q23 0 42 -4q31 61 88.5 96.5t125.5 35.5z" /> <glyph glyph-name="_562" unicode="" horiz-adv-x="1792" d="M1073 -128h-177q-163 0 -226 141q-23 49 -23 102v5q-62 30 -98.5 88.5t-36.5 127.5q0 38 5 48h-261q-106 0 -181 75t-75 181t75 181t181 75h113l-44 17q-74 28 -119.5 93.5t-45.5 145.5q0 106 75 181t181 75q46 0 91 -17l628 -239h401q106 0 181 -75t75 -181v-668 q0 -88 -54 -157.5t-140 -90.5l-339 -85q-92 -23 -186 -23zM1024 583l-155 -71l-163 -74q-30 -14 -48 -41.5t-18 -60.5q0 -46 33 -79t79 -33q26 0 46 10l338 154q-49 10 -80.5 50t-31.5 90v55zM1344 272q0 46 -33 79t-79 33q-26 0 -46 -10l-290 -132q-28 -13 -37 -17 t-30.5 -17t-29.5 -23.5t-16 -29t-8 -40.5q0 -50 31.5 -82t81.5 -32q20 0 38 9l352 160q30 14 48 41.5t18 60.5zM1112 1024l-650 248q-24 8 -46 8q-53 0 -90.5 -37.5t-37.5 -90.5q0 -40 22.5 -73t59.5 -47l526 -200v-64h-640q-53 0 -90.5 -37.5t-37.5 -90.5t37.5 -90.5 t90.5 -37.5h535l233 106v198q0 63 46 106l111 102h-69zM1073 0q82 0 155 19l339 85q43 11 70 45.5t27 78.5v668q0 53 -37.5 90.5t-90.5 37.5h-308l-136 -126q-36 -33 -36 -82v-296q0 -46 33 -77t79 -31t79 35t33 81v208h32v-208q0 -70 -57 -114q52 -8 86.5 -48.5t34.5 -93.5 q0 -42 -23 -78t-61 -53l-310 -141h91z" /> <glyph glyph-name="_563" unicode="" horiz-adv-x="2048" d="M1151 1536q61 0 116 -28t91 -77l572 -781q118 -159 118 -359v-355q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v177l-286 143h-546q-80 0 -136 56t-56 136v32q0 119 84.5 203.5t203.5 84.5h420l42 128h-686q-100 0 -173.5 67.5t-81.5 166.5q-65 79 -65 182v32 q0 80 56 136t136 56h959zM1920 -64v355q0 157 -93 284l-573 781q-39 52 -103 52h-959q-26 0 -45 -19t-19 -45q0 -32 1.5 -49.5t9.5 -40.5t25 -43q10 31 35.5 50t56.5 19h832v-32h-832q-26 0 -45 -19t-19 -45q0 -44 3 -58q8 -44 44 -73t81 -29h640h91q40 0 68 -28t28 -68 q0 -15 -5 -30l-64 -192q-10 -29 -35 -47.5t-56 -18.5h-443q-66 0 -113 -47t-47 -113v-32q0 -26 19 -45t45 -19h561q16 0 29 -7l317 -158q24 -13 38.5 -36t14.5 -50v-197q0 -26 19 -45t45 -19h384q26 0 45 19t19 45z" /> <glyph glyph-name="_564" unicode="" horiz-adv-x="2048" d="M459 -256q-77 0 -137.5 47.5t-79.5 122.5l-101 401q-13 57 -13 108q0 45 -5 67l-116 477q-7 27 -7 57q0 93 62 161t155 78q17 85 82.5 139t152.5 54q83 0 148 -51.5t85 -132.5l83 -348l103 428q20 81 85 132.5t148 51.5q89 0 155.5 -57.5t80.5 -144.5q92 -10 152 -79 t60 -162q0 -24 -7 -59l-123 -512q10 7 37.5 28.5t38.5 29.5t35 23t41 20.5t41.5 11t49.5 5.5q105 0 180 -74t75 -179q0 -62 -28.5 -118t-78.5 -94l-507 -380q-68 -51 -153 -51h-694zM1104 1408q-38 0 -68.5 -24t-39.5 -62l-164 -682h-127l-145 602q-9 38 -39.5 62t-68.5 24 q-48 0 -80 -33t-32 -80q0 -15 3 -28l132 -547h-26l-99 408q-9 37 -40 62.5t-69 25.5q-47 0 -80 -33t-33 -79q0 -14 3 -26l116 -478q7 -28 9 -86t10 -88l100 -401q8 -32 34 -52.5t59 -20.5h694q42 0 76 26l507 379q56 43 56 110q0 52 -37.5 88.5t-89.5 36.5q-43 0 -77 -26 l-307 -230v227q0 4 32 138t68 282t39 161q4 18 4 29q0 47 -32 81t-79 34q-39 0 -69.5 -24t-39.5 -62l-116 -482h-26l150 624q3 14 3 28q0 48 -31.5 82t-79.5 34z" /> <glyph glyph-name="_565" unicode="" horiz-adv-x="1792" d="M640 1408q-53 0 -90.5 -37.5t-37.5 -90.5v-512v-384l-151 202q-41 54 -107 54q-52 0 -89 -38t-37 -90q0 -43 26 -77l384 -512q38 -51 102 -51h718q22 0 39.5 13.5t22.5 34.5l92 368q24 96 24 194v217q0 41 -28 71t-68 30t-68 -28t-28 -68h-32v61q0 48 -32 81.5t-80 33.5 q-46 0 -79 -33t-33 -79v-64h-32v90q0 55 -37 94.5t-91 39.5q-53 0 -90.5 -37.5t-37.5 -90.5v-96h-32v570q0 55 -37 94.5t-91 39.5zM640 1536q107 0 181.5 -77.5t74.5 -184.5v-220q22 2 32 2q99 0 173 -69q47 21 99 21q113 0 184 -87q27 7 56 7q94 0 159 -67.5t65 -161.5 v-217q0 -116 -28 -225l-92 -368q-16 -64 -68 -104.5t-118 -40.5h-718q-60 0 -114.5 27.5t-90.5 74.5l-384 512q-51 68 -51 154q0 105 74.5 180.5t179.5 75.5q71 0 130 -35v547q0 106 75 181t181 75zM768 128v384h-32v-384h32zM1024 128v384h-32v-384h32zM1280 128v384h-32 v-384h32z" /> <glyph glyph-name="_566" unicode="" d="M1288 889q60 0 107 -23q141 -63 141 -226v-177q0 -94 -23 -186l-85 -339q-21 -86 -90.5 -140t-157.5 -54h-668q-106 0 -181 75t-75 181v401l-239 628q-17 45 -17 91q0 106 75 181t181 75q80 0 145.5 -45.5t93.5 -119.5l17 -44v113q0 106 75 181t181 75t181 -75t75 -181 v-261q27 5 48 5q69 0 127.5 -36.5t88.5 -98.5zM1072 896q-33 0 -60.5 -18t-41.5 -48l-74 -163l-71 -155h55q50 0 90 -31.5t50 -80.5l154 338q10 20 10 46q0 46 -33 79t-79 33zM1293 761q-22 0 -40.5 -8t-29 -16t-23.5 -29.5t-17 -30.5t-17 -37l-132 -290q-10 -20 -10 -46 q0 -46 33 -79t79 -33q33 0 60.5 18t41.5 48l160 352q9 18 9 38q0 50 -32 81.5t-82 31.5zM128 1120q0 -22 8 -46l248 -650v-69l102 111q43 46 106 46h198l106 233v535q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5v-640h-64l-200 526q-14 37 -47 59.5t-73 22.5 q-53 0 -90.5 -37.5t-37.5 -90.5zM1180 -128q44 0 78.5 27t45.5 70l85 339q19 73 19 155v91l-141 -310q-17 -38 -53 -61t-78 -23q-53 0 -93.5 34.5t-48.5 86.5q-44 -57 -114 -57h-208v32h208q46 0 81 33t35 79t-31 79t-77 33h-296q-49 0 -82 -36l-126 -136v-308 q0 -53 37.5 -90.5t90.5 -37.5h668z" /> <glyph glyph-name="_567" unicode="" horiz-adv-x="1973" d="M857 992v-117q0 -13 -9.5 -22t-22.5 -9h-298v-812q0 -13 -9 -22.5t-22 -9.5h-135q-13 0 -22.5 9t-9.5 23v812h-297q-13 0 -22.5 9t-9.5 22v117q0 14 9 23t23 9h793q13 0 22.5 -9.5t9.5 -22.5zM1895 995l77 -961q1 -13 -8 -24q-10 -10 -23 -10h-134q-12 0 -21 8.5 t-10 20.5l-46 588l-189 -425q-8 -19 -29 -19h-120q-20 0 -29 19l-188 427l-45 -590q-1 -12 -10 -20.5t-21 -8.5h-135q-13 0 -23 10q-9 10 -9 24l78 961q1 12 10 20.5t21 8.5h142q20 0 29 -19l220 -520q10 -24 20 -51q3 7 9.5 24.5t10.5 26.5l221 520q9 19 29 19h141 q13 0 22 -8.5t10 -20.5z" /> <glyph glyph-name="_568" unicode="" horiz-adv-x="1792" d="M1042 833q0 88 -60 121q-33 18 -117 18h-123v-281h162q66 0 102 37t36 105zM1094 548l205 -373q8 -17 -1 -31q-8 -16 -27 -16h-152q-20 0 -28 17l-194 365h-155v-350q0 -14 -9 -23t-23 -9h-134q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h294q128 0 190 -24q85 -31 134 -109 t49 -180q0 -92 -42.5 -165.5t-115.5 -109.5q6 -10 9 -16zM896 1376q-150 0 -286 -58.5t-234.5 -157t-157 -234.5t-58.5 -286t58.5 -286t157 -234.5t234.5 -157t286 -58.5t286 58.5t234.5 157t157 234.5t58.5 286t-58.5 286t-157 234.5t-234.5 157t-286 58.5zM1792 640 q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> <glyph glyph-name="_569" unicode="" horiz-adv-x="1792" d="M605 303q153 0 257 104q14 18 3 36l-45 82q-6 13 -24 17q-16 2 -27 -11l-4 -3q-4 -4 -11.5 -10t-17.5 -13.5t-23.5 -14.5t-28.5 -13t-33.5 -9.5t-37.5 -3.5q-76 0 -125 50t-49 127q0 76 48 125.5t122 49.5q37 0 71.5 -14t50.5 -28l16 -14q11 -11 26 -10q16 2 24 14l53 78 q13 20 -2 39q-3 4 -11 12t-30 23.5t-48.5 28t-67.5 22.5t-86 10q-148 0 -246 -96.5t-98 -240.5q0 -146 97 -241.5t247 -95.5zM1235 303q153 0 257 104q14 18 4 36l-45 82q-8 14 -25 17q-16 2 -27 -11l-4 -3q-4 -4 -11.5 -10t-17.5 -13.5t-23.5 -14.5t-28.5 -13t-33.5 -9.5 t-37.5 -3.5q-76 0 -125 50t-49 127q0 76 48 125.5t122 49.5q37 0 71.5 -14t50.5 -28l16 -14q11 -11 26 -10q16 2 24 14l53 78q13 20 -2 39q-3 4 -11 12t-30 23.5t-48.5 28t-67.5 22.5t-86 10q-147 0 -245.5 -96.5t-98.5 -240.5q0 -146 97 -241.5t247 -95.5zM896 1376 q-150 0 -286 -58.5t-234.5 -157t-157 -234.5t-58.5 -286t58.5 -286t157 -234.5t234.5 -157t286 -58.5t286 58.5t234.5 157t157 234.5t58.5 286t-58.5 286t-157 234.5t-234.5 157t-286 58.5zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191 t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71z" /> <glyph glyph-name="f260" unicode="" horiz-adv-x="2048" d="M736 736l384 -384l-384 -384l-672 672l672 672l168 -168l-96 -96l-72 72l-480 -480l480 -480l193 193l-289 287zM1312 1312l672 -672l-672 -672l-168 168l96 96l72 -72l480 480l-480 480l-193 -193l289 -287l-96 -96l-384 384z" /> <glyph glyph-name="f261" unicode="" horiz-adv-x="1792" d="M717 182l271 271l-279 279l-88 -88l192 -191l-96 -96l-279 279l279 279l40 -40l87 87l-127 128l-454 -454zM1075 190l454 454l-454 454l-271 -271l279 -279l88 88l-192 191l96 96l279 -279l-279 -279l-40 40l-87 -88zM1792 640q0 -182 -71 -348t-191 -286t-286 -191 t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> <glyph glyph-name="_572" unicode="" horiz-adv-x="2304" d="M651 539q0 -39 -27.5 -66.5t-65.5 -27.5q-39 0 -66.5 27.5t-27.5 66.5q0 38 27.5 65.5t66.5 27.5q38 0 65.5 -27.5t27.5 -65.5zM1805 540q0 -39 -27.5 -66.5t-66.5 -27.5t-66.5 27.5t-27.5 66.5t27.5 66t66.5 27t66.5 -27t27.5 -66zM765 539q0 79 -56.5 136t-136.5 57 t-136.5 -56.5t-56.5 -136.5t56.5 -136.5t136.5 -56.5t136.5 56.5t56.5 136.5zM1918 540q0 80 -56.5 136.5t-136.5 56.5q-79 0 -136 -56.5t-57 -136.5t56.5 -136.5t136.5 -56.5t136.5 56.5t56.5 136.5zM850 539q0 -116 -81.5 -197.5t-196.5 -81.5q-116 0 -197.5 82t-81.5 197 t82 196.5t197 81.5t196.5 -81.5t81.5 -196.5zM2004 540q0 -115 -81.5 -196.5t-197.5 -81.5q-115 0 -196.5 81.5t-81.5 196.5t81.5 196.5t196.5 81.5q116 0 197.5 -81.5t81.5 -196.5zM1040 537q0 191 -135.5 326.5t-326.5 135.5q-125 0 -231 -62t-168 -168.5t-62 -231.5 t62 -231.5t168 -168.5t231 -62q191 0 326.5 135.5t135.5 326.5zM1708 1110q-254 111 -556 111q-319 0 -573 -110q117 0 223 -45.5t182.5 -122.5t122 -183t45.5 -223q0 115 43.5 219.5t118 180.5t177.5 123t217 50zM2187 537q0 191 -135 326.5t-326 135.5t-326.5 -135.5 t-135.5 -326.5t135.5 -326.5t326.5 -135.5t326 135.5t135 326.5zM1921 1103h383q-44 -51 -75 -114.5t-40 -114.5q110 -151 110 -337q0 -156 -77 -288t-209 -208.5t-287 -76.5q-133 0 -249 56t-196 155q-47 -56 -129 -179q-11 22 -53.5 82.5t-74.5 97.5 q-80 -99 -196.5 -155.5t-249.5 -56.5q-155 0 -287 76.5t-209 208.5t-77 288q0 186 110 337q-9 51 -40 114.5t-75 114.5h365q149 100 355 156.5t432 56.5q224 0 421 -56t348 -157z" /> <glyph glyph-name="f263" unicode="" horiz-adv-x="1280" d="M640 629q-188 0 -321 133t-133 320q0 188 133 321t321 133t321 -133t133 -321q0 -187 -133 -320t-321 -133zM640 1306q-92 0 -157.5 -65.5t-65.5 -158.5q0 -92 65.5 -157.5t157.5 -65.5t157.5 65.5t65.5 157.5q0 93 -65.5 158.5t-157.5 65.5zM1163 574q13 -27 15 -49.5 t-4.5 -40.5t-26.5 -38.5t-42.5 -37t-61.5 -41.5q-115 -73 -315 -94l73 -72l267 -267q30 -31 30 -74t-30 -73l-12 -13q-31 -30 -74 -30t-74 30q-67 68 -267 268l-267 -268q-31 -30 -74 -30t-73 30l-12 13q-31 30 -31 73t31 74l267 267l72 72q-203 21 -317 94 q-39 25 -61.5 41.5t-42.5 37t-26.5 38.5t-4.5 40.5t15 49.5q10 20 28 35t42 22t56 -2t65 -35q5 -4 15 -11t43 -24.5t69 -30.5t92 -24t113 -11q91 0 174 25.5t120 50.5l38 25q33 26 65 35t56 2t42 -22t28 -35z" /> <glyph glyph-name="_574" unicode="" d="M927 956q0 -66 -46.5 -112.5t-112.5 -46.5t-112.5 46.5t-46.5 112.5t46.5 112.5t112.5 46.5t112.5 -46.5t46.5 -112.5zM1141 593q-10 20 -28 32t-47.5 9.5t-60.5 -27.5q-10 -8 -29 -20t-81 -32t-127 -20t-124 18t-86 36l-27 18q-31 25 -60.5 27.5t-47.5 -9.5t-28 -32 q-22 -45 -2 -74.5t87 -73.5q83 -53 226 -67l-51 -52q-142 -142 -191 -190q-22 -22 -22 -52.5t22 -52.5l9 -9q22 -22 52.5 -22t52.5 22l191 191q114 -115 191 -191q22 -22 52.5 -22t52.5 22l9 9q22 22 22 52.5t-22 52.5l-191 190l-52 52q141 14 225 67q67 44 87 73.5t-2 74.5 zM1092 956q0 134 -95 229t-229 95t-229 -95t-95 -229t95 -229t229 -95t229 95t95 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="_575" unicode="" horiz-adv-x="1720" d="M1565 1408q65 0 110 -45.5t45 -110.5v-519q0 -176 -68 -336t-182.5 -275t-274 -182.5t-334.5 -67.5q-176 0 -335.5 67.5t-274.5 182.5t-183 275t-68 336v519q0 64 46 110t110 46h1409zM861 344q47 0 82 33l404 388q37 35 37 85q0 49 -34.5 83.5t-83.5 34.5q-47 0 -82 -33 l-323 -310l-323 310q-35 33 -81 33q-49 0 -83.5 -34.5t-34.5 -83.5q0 -51 36 -85l405 -388q33 -33 81 -33z" /> <glyph glyph-name="_576" unicode="" horiz-adv-x="2304" d="M1494 -103l-295 695q-25 -49 -158.5 -305.5t-198.5 -389.5q-1 -1 -27.5 -0.5t-26.5 1.5q-82 193 -255.5 587t-259.5 596q-21 50 -66.5 107.5t-103.5 100.5t-102 43q0 5 -0.5 24t-0.5 27h583v-50q-39 -2 -79.5 -16t-66.5 -43t-10 -64q26 -59 216.5 -499t235.5 -540 q31 61 140 266.5t131 247.5q-19 39 -126 281t-136 295q-38 69 -201 71v50l513 -1v-47q-60 -2 -93.5 -25t-12.5 -69q33 -70 87 -189.5t86 -187.5q110 214 173 363q24 55 -10 79.5t-129 26.5q1 7 1 25v24q64 0 170.5 0.5t180 1t92.5 0.5v-49q-62 -2 -119 -33t-90 -81 l-213 -442q13 -33 127.5 -290t121.5 -274l441 1017q-14 38 -49.5 62.5t-65 31.5t-55.5 8v50l460 -4l1 -2l-1 -44q-139 -4 -201 -145q-526 -1216 -559 -1291h-49z" /> <glyph glyph-name="_577" unicode="" horiz-adv-x="1792" d="M949 643q0 -26 -16.5 -45t-41.5 -19q-26 0 -45 16.5t-19 41.5q0 26 17 45t42 19t44 -16.5t19 -41.5zM964 585l350 581q-9 -8 -67.5 -62.5t-125.5 -116.5t-136.5 -127t-117 -110.5t-50.5 -51.5l-349 -580q7 7 67 62t126 116.5t136 127t117 111t50 50.5zM1611 640 q0 -201 -104 -371q-3 2 -17 11t-26.5 16.5t-16.5 7.5q-13 0 -13 -13q0 -10 59 -44q-74 -112 -184.5 -190.5t-241.5 -110.5l-16 67q-1 10 -15 10q-5 0 -8 -5.5t-2 -9.5l16 -68q-72 -15 -146 -15q-199 0 -372 105q1 2 13 20.5t21.5 33.5t9.5 19q0 13 -13 13q-6 0 -17 -14.5 t-22.5 -34.5t-13.5 -23q-113 75 -192 187.5t-110 244.5l69 15q10 3 10 15q0 5 -5.5 8t-10.5 2l-68 -15q-14 72 -14 139q0 206 109 379q2 -1 18.5 -12t30 -19t17.5 -8q13 0 13 12q0 6 -12.5 15.5t-32.5 21.5l-20 12q77 112 189 189t244 107l15 -67q2 -10 15 -10q5 0 8 5.5 t2 10.5l-15 66q71 13 134 13q204 0 379 -109q-39 -56 -39 -65q0 -13 12 -13q11 0 48 64q111 -75 187.5 -186t107.5 -241l-56 -12q-10 -2 -10 -16q0 -5 5.5 -8t9.5 -2l57 13q14 -72 14 -140zM1696 640q0 163 -63.5 311t-170.5 255t-255 170.5t-311 63.5t-311 -63.5 t-255 -170.5t-170.5 -255t-63.5 -311t63.5 -311t170.5 -255t255 -170.5t311 -63.5t311 63.5t255 170.5t170.5 255t63.5 311zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191 t191 -286t71 -348z" /> <glyph glyph-name="_578" unicode="" horiz-adv-x="1792" d="M893 1536q240 2 451 -120q232 -134 352 -372l-742 39q-160 9 -294 -74.5t-185 -229.5l-276 424q128 159 311 245.5t383 87.5zM146 1131l337 -663q72 -143 211 -217t293 -45l-230 -451q-212 33 -385 157.5t-272.5 316t-99.5 411.5q0 267 146 491zM1732 962 q58 -150 59.5 -310.5t-48.5 -306t-153 -272t-246 -209.5q-230 -133 -498 -119l405 623q88 131 82.5 290.5t-106.5 277.5zM896 942q125 0 213.5 -88.5t88.5 -213.5t-88.5 -213.5t-213.5 -88.5t-213.5 88.5t-88.5 213.5t88.5 213.5t213.5 88.5z" /> <glyph glyph-name="_579" unicode="" horiz-adv-x="1792" d="M903 -256q-283 0 -504.5 150.5t-329.5 398.5q-58 131 -67 301t26 332.5t111 312t179 242.5l-11 -281q11 14 68 15.5t70 -15.5q42 81 160.5 138t234.5 59q-54 -45 -119.5 -148.5t-58.5 -163.5q25 -8 62.5 -13.5t63 -7.5t68 -4t50.5 -3q15 -5 9.5 -45.5t-30.5 -75.5 q-5 -7 -16.5 -18.5t-56.5 -35.5t-101 -34l15 -189l-139 67q-18 -43 -7.5 -81.5t36 -66.5t65.5 -41.5t81 -6.5q51 9 98 34.5t83.5 45t73.5 17.5q61 -4 89.5 -33t19.5 -65q-1 -2 -2.5 -5.5t-8.5 -12.5t-18 -15.5t-31.5 -10.5t-46.5 -1q-60 -95 -144.5 -135.5t-209.5 -29.5 q74 -61 162.5 -82.5t168.5 -6t154.5 52t128 87.5t80.5 104q43 91 39 192.5t-37.5 188.5t-78.5 125q87 -38 137 -79.5t77 -112.5q15 170 -57.5 343t-209.5 284q265 -77 412 -279.5t151 -517.5q2 -127 -40.5 -255t-123.5 -238t-189 -196t-247.5 -135.5t-288.5 -49.5z" /> <glyph glyph-name="_580" unicode="" horiz-adv-x="1792" d="M1493 1308q-165 110 -359 110q-155 0 -293 -73t-240 -200q-75 -93 -119.5 -218t-48.5 -266v-42q4 -141 48.5 -266t119.5 -218q102 -127 240 -200t293 -73q194 0 359 110q-121 -108 -274.5 -168t-322.5 -60q-29 0 -43 1q-175 8 -333 82t-272 193t-181 281t-67 339 q0 182 71 348t191 286t286 191t348 71h3q168 -1 320.5 -60.5t273.5 -167.5zM1792 640q0 -192 -77 -362.5t-213 -296.5q-104 -63 -222 -63q-137 0 -255 84q154 56 253.5 233t99.5 405q0 227 -99 404t-253 234q119 83 254 83q119 0 226 -65q135 -125 210.5 -295t75.5 -361z " /> <glyph glyph-name="_581" unicode="" horiz-adv-x="1792" d="M1792 599q0 -56 -7 -104h-1151q0 -146 109.5 -244.5t257.5 -98.5q99 0 185.5 46.5t136.5 130.5h423q-56 -159 -170.5 -281t-267.5 -188.5t-321 -66.5q-187 0 -356 83q-228 -116 -394 -116q-237 0 -237 263q0 115 45 275q17 60 109 229q199 360 475 606 q-184 -79 -427 -354q63 274 283.5 449.5t501.5 175.5q30 0 45 -1q255 117 433 117q64 0 116 -13t94.5 -40.5t66.5 -76.5t24 -115q0 -116 -75 -286q101 -182 101 -390zM1722 1239q0 83 -53 132t-137 49q-108 0 -254 -70q121 -47 222.5 -131.5t170.5 -195.5q51 135 51 216z M128 2q0 -86 48.5 -132.5t134.5 -46.5q115 0 266 83q-122 72 -213.5 183t-137.5 245q-98 -205 -98 -332zM632 715h728q-5 142 -113 237t-251 95q-144 0 -251.5 -95t-112.5 -237z" /> <glyph glyph-name="_582" unicode="" horiz-adv-x="2048" d="M1792 288v960q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1248v-960q0 -66 -47 -113t-113 -47h-736v-128h352q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23 v64q0 14 9 23t23 9h352v128h-736q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" /> <glyph glyph-name="_583" unicode="" horiz-adv-x="1792" d="M138 1408h197q-70 -64 -126 -149q-36 -56 -59 -115t-30 -125.5t-8.5 -120t10.5 -132t21 -126t28 -136.5q4 -19 6 -28q51 -238 81 -329q57 -171 152 -275h-272q-48 0 -82 34t-34 82v1304q0 48 34 82t82 34zM1346 1408h308q48 0 82 -34t34 -82v-1304q0 -48 -34 -82t-82 -34 h-178q212 210 196 565l-469 -101q-2 -45 -12 -82t-31 -72t-59.5 -59.5t-93.5 -36.5q-123 -26 -199 40q-32 27 -53 61t-51.5 129t-64.5 258q-35 163 -45.5 263t-5.5 139t23 77q20 41 62.5 73t102.5 45q45 12 83.5 6.5t67 -17t54 -35t43 -48t34.5 -56.5l468 100 q-68 175 -180 287z" /> <glyph glyph-name="_584" unicode="" d="M1401 -11l-6 -6q-113 -113 -259 -175q-154 -64 -317 -64q-165 0 -317 64q-148 63 -259 175q-113 112 -175 258q-42 103 -54 189q-4 28 48 36q51 8 56 -20q1 -1 1 -4q18 -90 46 -159q50 -124 152 -226q98 -98 226 -152q132 -56 276 -56q143 0 276 56q128 55 225 152l6 6 q10 10 25 6q12 -3 33 -22q36 -37 17 -58zM929 604l-66 -66l63 -63q21 -21 -7 -49q-17 -17 -32 -17q-10 0 -19 10l-62 61l-66 -66q-5 -5 -15 -5q-15 0 -31 16l-2 2q-18 15 -18 29q0 7 8 17l66 65l-66 66q-16 16 14 45q18 18 31 18q6 0 13 -5l65 -66l65 65q18 17 48 -13 q27 -27 11 -44zM1400 547q0 -118 -46 -228q-45 -105 -126 -186q-80 -80 -187 -126t-228 -46t-228 46t-187 126q-82 82 -125 186q-15 33 -15 40h-1q-9 27 43 44q50 16 60 -12q37 -99 97 -167h1v339v2q3 136 102 232q105 103 253 103q147 0 251 -103t104 -249 q0 -147 -104.5 -251t-250.5 -104q-58 0 -112 16q-28 11 -13 61q16 51 44 43l14 -3q14 -3 33 -6t30 -3q104 0 176 71.5t72 174.5q0 101 -72 171q-71 71 -175 71q-107 0 -178 -80q-64 -72 -64 -160v-413q110 -67 242 -67q96 0 185 36.5t156 103.5t103.5 155t36.5 183 q0 198 -141 339q-140 140 -339 140q-200 0 -340 -140q-53 -53 -77 -87l-2 -2q-8 -11 -13 -15.5t-21.5 -9.5t-38.5 3q-21 5 -36.5 16.5t-15.5 26.5v680q0 15 10.5 26.5t27.5 11.5h877q30 0 30 -55t-30 -55h-811v-483h1q40 42 102 84t108 61q109 46 231 46q121 0 228 -46 t187 -126q81 -81 126 -186q46 -112 46 -229zM1369 1128q9 -8 9 -18t-5.5 -18t-16.5 -21q-26 -26 -39 -26q-9 0 -16 7q-106 91 -207 133q-128 56 -276 56q-133 0 -262 -49q-27 -10 -45 37q-9 25 -8 38q3 16 16 20q130 57 299 57q164 0 316 -64q137 -58 235 -152z" /> <glyph glyph-name="_585" unicode="" horiz-adv-x="1792" d="M1551 60q15 6 26 3t11 -17.5t-15 -33.5q-13 -16 -44 -43.5t-95.5 -68t-141 -74t-188 -58t-229.5 -24.5q-119 0 -238 31t-209 76.5t-172.5 104t-132.5 105t-84 87.5q-8 9 -10 16.5t1 12t8 7t11.5 2t11.5 -4.5q192 -117 300 -166q389 -176 799 -90q190 40 391 135z M1758 175q11 -16 2.5 -69.5t-28.5 -102.5q-34 -83 -85 -124q-17 -14 -26 -9t0 24q21 45 44.5 121.5t6.5 98.5q-5 7 -15.5 11.5t-27 6t-29.5 2.5t-35 0t-31.5 -2t-31 -3t-22.5 -2q-6 -1 -13 -1.5t-11 -1t-8.5 -1t-7 -0.5h-5.5h-4.5t-3 0.5t-2 1.5l-1.5 3q-6 16 47 40t103 30 q46 7 108 1t76 -24zM1364 618q0 -31 13.5 -64t32 -58t37.5 -46t33 -32l13 -11l-227 -224q-40 37 -79 75.5t-58 58.5l-19 20q-11 11 -25 33q-38 -59 -97.5 -102.5t-127.5 -63.5t-140 -23t-137.5 21t-117.5 65.5t-83 113t-31 162.5q0 84 28 154t72 116.5t106.5 83t122.5 57 t130 34.5t119.5 18.5t99.5 6.5v127q0 65 -21 97q-34 53 -121 53q-6 0 -16.5 -1t-40.5 -12t-56 -29.5t-56 -59.5t-48 -96l-294 27q0 60 22 119t67 113t108 95t151.5 65.5t190.5 24.5q100 0 181 -25t129.5 -61.5t81 -83t45 -86t12.5 -73.5v-589zM692 597q0 -86 70 -133 q66 -44 139 -22q84 25 114 123q14 45 14 101v162q-59 -2 -111 -12t-106.5 -33.5t-87 -71t-32.5 -114.5z" /> <glyph glyph-name="_586" unicode="" horiz-adv-x="1792" d="M1536 1280q52 0 90 -38t38 -90v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128zM1152 1376v-288q0 -14 9 -23t23 -9 h64q14 0 23 9t9 23v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 1376v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM1536 -128v1024h-1408v-1024h1408zM896 448h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224 v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v224q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-224z" /> <glyph glyph-name="_587" unicode="" horiz-adv-x="1792" d="M1152 416v-64q0 -14 -9 -23t-23 -9h-576q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h576q14 0 23 -9t9 -23zM128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23 t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47 t47 -113v-96h128q52 0 90 -38t38 -90z" /> <glyph glyph-name="_588" unicode="" horiz-adv-x="1792" d="M1111 151l-46 -46q-9 -9 -22 -9t-23 9l-188 189l-188 -189q-10 -9 -23 -9t-22 9l-46 46q-9 9 -9 22t9 23l189 188l-189 188q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l188 -188l188 188q10 9 23 9t22 -9l46 -46q9 -9 9 -22t-9 -23l-188 -188l188 -188q9 -10 9 -23t-9 -22z M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" /> <glyph glyph-name="_589" unicode="" horiz-adv-x="1792" d="M1303 572l-512 -512q-10 -9 -23 -9t-23 9l-288 288q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l220 -220l444 444q10 9 23 9t22 -9l46 -46q9 -9 9 -22t-9 -23zM128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23 t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47 t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" /> <glyph glyph-name="_590" unicode="" horiz-adv-x="1792" d="M448 1536q26 0 45 -19t19 -45v-891l536 429q17 14 40 14q26 0 45 -19t19 -45v-379l536 429q17 14 40 14q26 0 45 -19t19 -45v-1152q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h384z" /> <glyph glyph-name="_591" unicode="" horiz-adv-x="1024" d="M512 448q66 0 128 15v-655q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v655q62 -15 128 -15zM512 1536q212 0 362 -150t150 -362t-150 -362t-362 -150t-362 150t-150 362t150 362t362 150zM512 1312q14 0 23 9t9 23t-9 23t-23 9q-146 0 -249 -103t-103 -249 q0 -14 9 -23t23 -9t23 9t9 23q0 119 84.5 203.5t203.5 84.5z" /> <glyph glyph-name="_592" unicode="" horiz-adv-x="1792" d="M1745 1239q10 -10 10 -23t-10 -23l-141 -141q-28 -28 -68 -28h-1344q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h576v64q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-64h512q40 0 68 -28zM768 320h256v-512q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v512zM1600 768 q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-1344q-40 0 -68 28l-141 141q-10 10 -10 23t10 23l141 141q28 28 68 28h512v192h256v-192h576z" /> <glyph glyph-name="_593" unicode="" horiz-adv-x="2048" d="M2020 1525q28 -20 28 -53v-1408q0 -20 -11 -36t-29 -23l-640 -256q-24 -11 -48 0l-616 246l-616 -246q-10 -5 -24 -5q-19 0 -36 11q-28 20 -28 53v1408q0 20 11 36t29 23l640 256q24 11 48 0l616 -246l616 246q32 13 60 -6zM736 1390v-1270l576 -230v1270zM128 1173 v-1270l544 217v1270zM1920 107v1270l-544 -217v-1270z" /> <glyph glyph-name="_594" unicode="" horiz-adv-x="1792" d="M512 1536q13 0 22.5 -9.5t9.5 -22.5v-1472q0 -20 -17 -28l-480 -256q-7 -4 -15 -4q-13 0 -22.5 9.5t-9.5 22.5v1472q0 20 17 28l480 256q7 4 15 4zM1760 1536q13 0 22.5 -9.5t9.5 -22.5v-1472q0 -20 -17 -28l-480 -256q-7 -4 -15 -4q-13 0 -22.5 9.5t-9.5 22.5v1472 q0 20 17 28l480 256q7 4 15 4zM640 1536q8 0 14 -3l512 -256q18 -10 18 -29v-1472q0 -13 -9.5 -22.5t-22.5 -9.5q-8 0 -14 3l-512 256q-18 10 -18 29v1472q0 13 9.5 22.5t22.5 9.5z" /> <glyph glyph-name="_595" unicode="" horiz-adv-x="1792" d="M640 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 640q0 53 -37.5 90.5t-90.5 37.5 t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-110 0 -211 18q-173 -173 -435 -229q-52 -10 -86 -13q-12 -1 -22 6t-13 18q-4 15 20 37q5 5 23.5 21.5t25.5 23.5t23.5 25.5t24 31.5t20.5 37 t20 48t14.5 57.5t12.5 72.5q-146 90 -229.5 216.5t-83.5 269.5q0 174 120 321.5t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" /> <glyph glyph-name="_596" unicode="" horiz-adv-x="1792" d="M640 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1024 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 -53 -37.5 -90.5t-90.5 -37.5 t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5 t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51 t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 130 71 248.5t191 204.5t286 136.5t348 50.5t348 -50.5t286 -136.5t191 -204.5t71 -248.5z" /> <glyph glyph-name="_597" unicode="" horiz-adv-x="1024" d="M512 345l512 295v-591l-512 -296v592zM0 640v-591l512 296zM512 1527v-591l-512 -296v591zM512 936l512 295v-591z" /> <glyph glyph-name="_598" unicode="" horiz-adv-x="1792" d="M1709 1018q-10 -236 -332 -651q-333 -431 -562 -431q-142 0 -240 263q-44 160 -132 482q-72 262 -157 262q-18 0 -127 -76l-77 98q24 21 108 96.5t130 115.5q156 138 241 146q95 9 153 -55.5t81 -203.5q44 -287 66 -373q55 -249 120 -249q51 0 154 161q101 161 109 246 q13 139 -109 139q-57 0 -121 -26q120 393 459 382q251 -8 236 -326z" /> <glyph glyph-name="f27e" unicode="" d="M0 1408h1536v-1536h-1536v1536zM1085 293l-221 631l221 297h-634l221 -297l-221 -631l317 -304z" /> <glyph glyph-name="uniF280" unicode="" d="M0 1408h1536v-1536h-1536v1536zM908 1088l-12 -33l75 -83l-31 -114l25 -25l107 57l107 -57l25 25l-31 114l75 83l-12 33h-95l-53 96h-32l-53 -96h-95zM641 925q32 0 44.5 -16t11.5 -63l174 21q0 55 -17.5 92.5t-50.5 56t-69 25.5t-85 7q-133 0 -199 -57.5t-66 -182.5v-72 h-96v-128h76q20 0 20 -8v-382q0 -14 -5 -20t-18 -7l-73 -7v-88h448v86l-149 14q-6 1 -8.5 1.5t-3.5 2.5t-0.5 4t1 7t0.5 10v387h191l38 128h-231q-6 0 -2 6t4 9v80q0 27 1.5 40.5t7.5 28t19.5 20t36.5 5.5zM1248 96v86l-54 9q-7 1 -9.5 2.5t-2.5 3t1 7.5t1 12v520h-275 l-23 -101l83 -22q23 -7 23 -27v-370q0 -14 -6 -18.5t-20 -6.5l-70 -9v-86h352z" /> <glyph glyph-name="uniF281" unicode="" horiz-adv-x="1792" d="M1792 690q0 -58 -29.5 -105.5t-79.5 -72.5q12 -46 12 -96q0 -155 -106.5 -287t-290.5 -208.5t-400 -76.5t-399.5 76.5t-290 208.5t-106.5 287q0 47 11 94q-51 25 -82 73.5t-31 106.5q0 82 58 140.5t141 58.5q85 0 145 -63q218 152 515 162l116 521q3 13 15 21t26 5 l369 -81q18 37 54 59.5t79 22.5q62 0 106 -43.5t44 -105.5t-44 -106t-106 -44t-105.5 43.5t-43.5 105.5l-334 74l-104 -472q300 -9 519 -160q58 61 143 61q83 0 141 -58.5t58 -140.5zM418 491q0 -62 43.5 -106t105.5 -44t106 44t44 106t-44 105.5t-106 43.5q-61 0 -105 -44 t-44 -105zM1228 136q11 11 11 26t-11 26q-10 10 -25 10t-26 -10q-41 -42 -121 -62t-160 -20t-160 20t-121 62q-11 10 -26 10t-25 -10q-11 -10 -11 -25.5t11 -26.5q43 -43 118.5 -68t122.5 -29.5t91 -4.5t91 4.5t122.5 29.5t118.5 68zM1225 341q62 0 105.5 44t43.5 106 q0 61 -44 105t-105 44q-62 0 -106 -43.5t-44 -105.5t44 -106t106 -44z" /> <glyph glyph-name="_602" unicode="" horiz-adv-x="1792" d="M69 741h1q16 126 58.5 241.5t115 217t167.5 176t223.5 117.5t276.5 43q231 0 414 -105.5t294 -303.5q104 -187 104 -442v-188h-1125q1 -111 53.5 -192.5t136.5 -122.5t189.5 -57t213 -3t208 46.5t173.5 84.5v-377q-92 -55 -229.5 -92t-312.5 -38t-316 53 q-189 73 -311.5 249t-124.5 372q-3 242 111 412t325 268q-48 -60 -78 -125.5t-46 -159.5h635q8 77 -8 140t-47 101.5t-70.5 66.5t-80.5 41t-75 20.5t-56 8.5l-22 1q-135 -5 -259.5 -44.5t-223.5 -104.5t-176 -140.5t-138 -163.5z" /> <glyph glyph-name="_603" unicode="" horiz-adv-x="2304" d="M0 32v608h2304v-608q0 -66 -47 -113t-113 -47h-1984q-66 0 -113 47t-47 113zM640 256v-128h384v128h-384zM256 256v-128h256v128h-256zM2144 1408q66 0 113 -47t47 -113v-224h-2304v224q0 66 47 113t113 47h1984z" /> <glyph glyph-name="_604" unicode="" horiz-adv-x="1792" d="M1584 246l-218 111q-74 -120 -196.5 -189t-263.5 -69q-147 0 -271 72t-196 196t-72 270q0 110 42.5 209.5t115 172t172 115t209.5 42.5q131 0 247.5 -60.5t192.5 -168.5l215 125q-110 169 -286.5 265t-378.5 96q-161 0 -308 -63t-253 -169t-169 -253t-63 -308t63 -308 t169 -253t253 -169t308 -63q213 0 397.5 107t290.5 292zM1030 643l693 -352q-116 -253 -334.5 -400t-492.5 -147q-182 0 -348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71q260 0 470.5 -133.5t335.5 -366.5zM1543 640h-39v-160h-96v352h136q32 0 54.5 -20 t28.5 -48t1 -56t-27.5 -48t-57.5 -20z" /> <glyph glyph-name="uniF285" unicode="" horiz-adv-x="1792" d="M1427 827l-614 386l92 151h855zM405 562l-184 116v858l1183 -743zM1424 697l147 -95v-858l-532 335zM1387 718l-500 -802h-855l356 571z" /> <glyph glyph-name="uniF286" unicode="" horiz-adv-x="1792" d="M640 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1152 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1664 496v-752h-640v320q0 80 -56 136t-136 56t-136 -56t-56 -136v-320h-640v752q0 16 16 16h96 q16 0 16 -16v-112h128v624q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 6 2.5 9.5t8.5 5t9.5 2t11.5 0t9 -0.5v391q-32 15 -32 50q0 23 16.5 39t38.5 16t38.5 -16t16.5 -39q0 -35 -32 -50v-17q45 10 83 10q21 0 59.5 -7.5t54.5 -7.5 q17 0 47 7.5t37 7.5q16 0 16 -16v-210q0 -15 -35 -21.5t-62 -6.5q-18 0 -54.5 7.5t-55.5 7.5q-40 0 -90 -12v-133q1 0 9 0.5t11.5 0t9.5 -2t8.5 -5t2.5 -9.5v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-624h128v112q0 16 16 16h96 q16 0 16 -16z" /> <glyph glyph-name="_607" unicode="" horiz-adv-x="2304" d="M2288 731q16 -8 16 -27t-16 -27l-320 -192q-8 -5 -16 -5q-9 0 -16 4q-16 10 -16 28v128h-858q37 -58 83 -165q16 -37 24.5 -55t24 -49t27 -47t27 -34t31.5 -26t33 -8h96v96q0 14 9 23t23 9h320q14 0 23 -9t9 -23v-320q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v96h-96 q-32 0 -61 10t-51 23.5t-45 40.5t-37 46t-33.5 57t-28.5 57.5t-28 60.5q-23 53 -37 81.5t-36 65t-44.5 53.5t-46.5 17h-360q-22 -84 -91 -138t-157 -54q-106 0 -181 75t-75 181t75 181t181 75q88 0 157 -54t91 -138h104q24 0 46.5 17t44.5 53.5t36 65t37 81.5q19 41 28 60.5 t28.5 57.5t33.5 57t37 46t45 40.5t51 23.5t61 10h107q21 57 70 92.5t111 35.5q80 0 136 -56t56 -136t-56 -136t-136 -56q-62 0 -111 35.5t-70 92.5h-107q-17 0 -33 -8t-31.5 -26t-27 -34t-27 -47t-24 -49t-24.5 -55q-46 -107 -83 -165h1114v128q0 18 16 28t32 -1z" /> <glyph glyph-name="_608" unicode="" horiz-adv-x="1792" d="M1150 774q0 -56 -39.5 -95t-95.5 -39h-253v269h253q56 0 95.5 -39.5t39.5 -95.5zM1329 774q0 130 -91.5 222t-222.5 92h-433v-896h180v269h253q130 0 222 91.5t92 221.5zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348 t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> <glyph glyph-name="_609" unicode="" horiz-adv-x="2304" d="M1645 438q0 59 -34 106.5t-87 68.5q-7 -45 -23 -92q-7 -24 -27.5 -38t-44.5 -14q-12 0 -24 3q-31 10 -45 38.5t-4 58.5q23 71 23 143q0 123 -61 227.5t-166 165.5t-228 61q-134 0 -247 -73t-167 -194q108 -28 188 -106q22 -23 22 -55t-22 -54t-54 -22t-55 22 q-75 75 -180 75q-106 0 -181 -74.5t-75 -180.5t75 -180.5t181 -74.5h1046q79 0 134.5 55.5t55.5 133.5zM1798 438q0 -142 -100.5 -242t-242.5 -100h-1046q-169 0 -289 119.5t-120 288.5q0 153 100 267t249 136q62 184 221 298t354 114q235 0 408.5 -158.5t196.5 -389.5 q116 -25 192.5 -118.5t76.5 -214.5zM2048 438q0 -175 -97 -319q-23 -33 -64 -33q-24 0 -43 13q-26 17 -32 48.5t12 57.5q71 104 71 233t-71 233q-18 26 -12 57t32 49t57.5 11.5t49.5 -32.5q97 -142 97 -318zM2304 438q0 -244 -134 -443q-23 -34 -64 -34q-23 0 -42 13 q-26 18 -32.5 49t11.5 57q108 164 108 358q0 195 -108 357q-18 26 -11.5 57.5t32.5 48.5q26 18 57 12t49 -33q134 -198 134 -442z" /> <glyph glyph-name="_610" unicode="" d="M1500 -13q0 -89 -63 -152.5t-153 -63.5t-153.5 63.5t-63.5 152.5q0 90 63.5 153.5t153.5 63.5t153 -63.5t63 -153.5zM1267 268q-115 -15 -192.5 -102.5t-77.5 -205.5q0 -74 33 -138q-146 -78 -379 -78q-109 0 -201 21t-153.5 54.5t-110.5 76.5t-76 85t-44.5 83 t-23.5 66.5t-6 39.5q0 19 4.5 42.5t18.5 56t36.5 58t64 43.5t94.5 18t94 -17.5t63 -41t35.5 -53t17.5 -49t4 -33.5q0 -34 -23 -81q28 -27 82 -42t93 -17l40 -1q115 0 190 51t75 133q0 26 -9 48.5t-31.5 44.5t-49.5 41t-74 44t-93.5 47.5t-119.5 56.5q-28 13 -43 20 q-116 55 -187 100t-122.5 102t-72 125.5t-20.5 162.5q0 78 20.5 150t66 137.5t112.5 114t166.5 77t221.5 28.5q120 0 220 -26t164.5 -67t109.5 -94t64 -105.5t19 -103.5q0 -46 -15 -82.5t-36.5 -58t-48.5 -36t-49 -19.5t-39 -5h-8h-32t-39 5t-44 14t-41 28t-37 46t-24 70.5 t-10 97.5q-15 16 -59 25.5t-81 10.5l-37 1q-68 0 -117.5 -31t-70.5 -70t-21 -76q0 -24 5 -43t24 -46t53 -51t97 -53.5t150 -58.5q76 -25 138.5 -53.5t109 -55.5t83 -59t60.5 -59.5t41 -62.5t26.5 -62t14.5 -63.5t6 -62t1 -62.5z" /> <glyph glyph-name="_611" unicode="" d="M704 352v576q0 14 -9 23t-23 9h-256q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h256q14 0 23 9t9 23zM1152 352v576q0 14 -9 23t-23 9h-256q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h256q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103 t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="_612" unicode="" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM768 96q148 0 273 73t198 198t73 273t-73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273 t73 -273t198 -198t273 -73zM864 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-192zM480 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-192z" /> <glyph glyph-name="_613" unicode="" d="M1088 352v576q0 14 -9 23t-23 9h-576q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h576q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" /> <glyph glyph-name="_614" unicode="" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM768 96q148 0 273 73t198 198t73 273t-73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273 t73 -273t198 -198t273 -73zM480 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h576q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-576z" /> <glyph glyph-name="_615" unicode="" horiz-adv-x="1792" d="M1757 128l35 -313q3 -28 -16 -50q-19 -21 -48 -21h-1664q-29 0 -48 21q-19 22 -16 50l35 313h1722zM1664 967l86 -775h-1708l86 775q3 24 21 40.5t43 16.5h256v-128q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5v128h384v-128q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5v128h256q25 0 43 -16.5t21 -40.5zM1280 1152v-256q0 -26 -19 -45t-45 -19t-45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-256q0 -26 -19 -45t-45 -19t-45 19t-19 45v256q0 159 112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" /> <glyph glyph-name="_616" unicode="" horiz-adv-x="2048" d="M1920 768q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5h-15l-115 -662q-8 -46 -44 -76t-82 -30h-1280q-46 0 -82 30t-44 76l-115 662h-15q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5h1792zM485 -32q26 2 43.5 22.5t15.5 46.5l-32 416q-2 26 -22.5 43.5 t-46.5 15.5t-43.5 -22.5t-15.5 -46.5l32 -416q2 -25 20.5 -42t43.5 -17h5zM896 32v416q0 26 -19 45t-45 19t-45 -19t-19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45zM1280 32v416q0 26 -19 45t-45 19t-45 -19t-19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45zM1632 27l32 416 q2 26 -15.5 46.5t-43.5 22.5t-46.5 -15.5t-22.5 -43.5l-32 -416q-2 -26 15.5 -46.5t43.5 -22.5h5q25 0 43.5 17t20.5 42zM476 1244l-93 -412h-132l101 441q19 88 89 143.5t160 55.5h167q0 26 19 45t45 19h384q26 0 45 -19t19 -45h167q90 0 160 -55.5t89 -143.5l101 -441 h-132l-93 412q-11 44 -45.5 72t-79.5 28h-167q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45h-167q-45 0 -79.5 -28t-45.5 -72z" /> <glyph glyph-name="_617" unicode="" horiz-adv-x="1792" d="M991 512l64 256h-254l-64 -256h254zM1759 1016l-56 -224q-7 -24 -31 -24h-327l-64 -256h311q15 0 25 -12q10 -14 6 -28l-56 -224q-5 -24 -31 -24h-327l-81 -328q-7 -24 -31 -24h-224q-16 0 -26 12q-9 12 -6 28l78 312h-254l-81 -328q-7 -24 -31 -24h-225q-15 0 -25 12 q-9 12 -6 28l78 312h-311q-15 0 -25 12q-9 12 -6 28l56 224q7 24 31 24h327l64 256h-311q-15 0 -25 12q-10 14 -6 28l56 224q5 24 31 24h327l81 328q7 24 32 24h224q15 0 25 -12q9 -12 6 -28l-78 -312h254l81 328q7 24 32 24h224q15 0 25 -12q9 -12 6 -28l-78 -312h311 q15 0 25 -12q9 -12 6 -28z" /> <glyph glyph-name="_618" unicode="" d="M841 483l148 -148l-149 -149zM840 1094l149 -149l-148 -148zM710 -130l464 464l-306 306l306 306l-464 464v-611l-255 255l-93 -93l320 -321l-320 -321l93 -93l255 255v-611zM1429 640q0 -209 -32 -365.5t-87.5 -257t-140.5 -162.5t-181.5 -86.5t-219.5 -24.5 t-219.5 24.5t-181.5 86.5t-140.5 162.5t-87.5 257t-32 365.5t32 365.5t87.5 257t140.5 162.5t181.5 86.5t219.5 24.5t219.5 -24.5t181.5 -86.5t140.5 -162.5t87.5 -257t32 -365.5z" /> <glyph glyph-name="_619" unicode="" horiz-adv-x="1024" d="M596 113l173 172l-173 172v-344zM596 823l173 172l-173 172v-344zM628 640l356 -356l-539 -540v711l-297 -296l-108 108l372 373l-372 373l108 108l297 -296v711l539 -540z" /> <glyph glyph-name="_620" unicode="" d="M1280 256q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM512 1024q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5 t112.5 -271.5zM1440 1344q0 -20 -13 -38l-1056 -1408q-19 -26 -51 -26h-160q-26 0 -45 19t-19 45q0 20 13 38l1056 1408q19 26 51 26h160q26 0 45 -19t19 -45zM768 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" /> <glyph glyph-name="_621" unicode="" horiz-adv-x="1792" d="M104 830l792 -1015l-868 630q-18 13 -25 34.5t0 42.5l101 308v0zM566 830h660l-330 -1015v0zM368 1442l198 -612h-462l198 612q8 23 33 23t33 -23zM1688 830l101 -308q7 -21 0 -42.5t-25 -34.5l-868 -630l792 1015v0zM1688 830h-462l198 612q8 23 33 23t33 -23z" /> <glyph glyph-name="_622" unicode="" horiz-adv-x="1792" d="M384 704h160v224h-160v-224zM1221 372v92q-104 -36 -243 -38q-135 -1 -259.5 46.5t-220.5 122.5l1 -96q88 -80 212 -128.5t272 -47.5q129 0 238 49zM640 704h640v224h-640v-224zM1792 736q0 -187 -99 -352q89 -102 89 -229q0 -157 -129.5 -268t-313.5 -111 q-122 0 -225 52.5t-161 140.5q-19 -1 -57 -1t-57 1q-58 -88 -161 -140.5t-225 -52.5q-184 0 -313.5 111t-129.5 268q0 127 89 229q-99 165 -99 352q0 209 120 385.5t326.5 279.5t449.5 103t449.5 -103t326.5 -279.5t120 -385.5z" /> <glyph glyph-name="_623" unicode="" d="M515 625v-128h-252v128h252zM515 880v-127h-252v127h252zM1273 369v-128h-341v128h341zM1273 625v-128h-672v128h672zM1273 880v-127h-672v127h672zM1408 20v1240q0 8 -6 14t-14 6h-32l-378 -256l-210 171l-210 -171l-378 256h-32q-8 0 -14 -6t-6 -14v-1240q0 -8 6 -14 t14 -6h1240q8 0 14 6t6 14zM553 1130l185 150h-406zM983 1130l221 150h-406zM1536 1260v-1240q0 -62 -43 -105t-105 -43h-1240q-62 0 -105 43t-43 105v1240q0 62 43 105t105 43h1240q62 0 105 -43t43 -105z" /> <glyph glyph-name="_624" unicode="" horiz-adv-x="1792" d="M896 720q-104 196 -160 278q-139 202 -347 318q-34 19 -70 36q-89 40 -94 32t34 -38l39 -31q62 -43 112.5 -93.5t94.5 -116.5t70.5 -113t70.5 -131q9 -17 13 -25q44 -84 84 -153t98 -154t115.5 -150t131 -123.5t148.5 -90.5q153 -66 154 -60q1 3 -49 37q-53 36 -81 57 q-77 58 -179 211t-185 310zM549 177q-76 60 -132.5 125t-98 143.5t-71 154.5t-58.5 186t-52 209t-60.5 252t-76.5 289q273 0 497.5 -36t379 -92t271 -144.5t185.5 -172.5t110 -198.5t56 -199.5t12.5 -198.5t-9.5 -173t-20 -143.5t-13 -107l323 -327h-104l-281 285 q-22 -2 -91.5 -14t-121.5 -19t-138 -6t-160.5 17t-167.5 59t-179 111z" /> <glyph glyph-name="_625" unicode="" horiz-adv-x="1792" d="M1374 879q-6 26 -28.5 39.5t-48.5 7.5q-261 -62 -401 -62t-401 62q-26 6 -48.5 -7.5t-28.5 -39.5t7.5 -48.5t39.5 -28.5q194 -46 303 -58q-2 -158 -15.5 -269t-26.5 -155.5t-41 -115.5l-9 -21q-10 -25 1 -49t36 -34q9 -4 23 -4q44 0 60 41l8 20q54 139 71 259h42 q17 -120 71 -259l8 -20q16 -41 60 -41q14 0 23 4q25 10 36 34t1 49l-9 21q-28 71 -41 115.5t-26.5 155.5t-15.5 269q109 12 303 58q26 6 39.5 28.5t7.5 48.5zM1024 1024q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z M1600 640q0 -143 -55.5 -273.5t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5zM896 1408q-156 0 -298 -61t-245 -164t-164 -245t-61 -298t61 -298 t164 -245t245 -164t298 -61t298 61t245 164t164 245t61 298t-61 298t-164 245t-245 164t-298 61zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> <glyph glyph-name="_626" unicode="" d="M1438 723q34 -35 29 -82l-44 -551q-4 -42 -34.5 -70t-71.5 -28q-6 0 -9 1q-44 3 -72.5 36.5t-25.5 77.5l35 429l-143 -8q55 -113 55 -240q0 -216 -148 -372l-137 137q91 101 91 235q0 145 -102.5 248t-247.5 103q-134 0 -236 -92l-137 138q120 114 284 141l264 300 l-149 87l-181 -161q-33 -30 -77 -27.5t-73 35.5t-26.5 77t34.5 73l239 213q26 23 60 26.5t64 -14.5l488 -283q36 -21 48 -68q17 -67 -26 -117l-205 -232l371 20q49 3 83 -32zM1240 1180q-74 0 -126 52t-52 126t52 126t126 52t126.5 -52t52.5 -126t-52.5 -126t-126.5 -52z M613 -62q106 0 196 61l139 -139q-146 -116 -335 -116q-148 0 -273.5 73t-198.5 198t-73 273q0 188 116 336l139 -139q-60 -88 -60 -197q0 -145 102.5 -247.5t247.5 -102.5z" /> <glyph glyph-name="_627" unicode="" d="M880 336v-160q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v160q0 14 9 23t23 9h160q14 0 23 -9t9 -23zM1136 832q0 -50 -15 -90t-45.5 -69t-52 -44t-59.5 -36q-32 -18 -46.5 -28t-26 -24t-11.5 -29v-32q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v68q0 35 10.5 64.5 t24 47.5t39 35.5t41 25.5t44.5 21q53 25 75 43t22 49q0 42 -43.5 71.5t-95.5 29.5q-56 0 -95 -27q-29 -20 -80 -83q-9 -12 -25 -12q-11 0 -19 6l-108 82q-10 7 -12 20t5 23q122 192 349 192q129 0 238.5 -89.5t109.5 -214.5zM768 1280q-130 0 -248.5 -51t-204 -136.5 t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5 t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="_628" unicode="" horiz-adv-x="1408" d="M366 1225q-64 0 -110 45.5t-46 110.5q0 64 46 109.5t110 45.5t109.5 -45.5t45.5 -109.5q0 -65 -45.5 -110.5t-109.5 -45.5zM917 583q0 -50 -30 -67.5t-63.5 -6.5t-47.5 34l-367 438q-7 12 -14 15.5t-11 1.5l-3 -3q-7 -8 4 -21l122 -139l1 -354l-161 -457 q-67 -192 -92 -234q-15 -26 -28 -32q-50 -26 -103 -1q-29 13 -41.5 43t-9.5 57q2 17 197 618l5 416l-85 -164l35 -222q4 -24 -1 -42t-14 -27.5t-19 -16t-17 -7.5l-7 -2q-19 -3 -34.5 3t-24 16t-14 22t-7.5 19.5t-2 9.5l-46 299l211 381q23 34 113 34q75 0 107 -40l424 -521 q7 -5 14 -17l3 -3l-1 -1q7 -13 7 -29zM514 433q43 -113 88.5 -225t69.5 -168l24 -55q36 -93 42 -125q11 -70 -36 -97q-35 -22 -66 -16t-51 22t-29 35h-1q-6 16 -8 25l-124 351zM1338 -159q31 -49 31 -57q0 -5 -3 -7q-9 -5 -14.5 0.5t-15.5 26t-16 30.5q-114 172 -423 661 q3 -1 7 1t7 4l3 2q11 9 11 17z" /> <glyph glyph-name="_629" unicode="" horiz-adv-x="2304" d="M504 542h171l-1 265zM1530 641q0 87 -50.5 140t-146.5 53h-54v-388h52q91 0 145 57t54 138zM956 1018l1 -756q0 -14 -9.5 -24t-23.5 -10h-216q-14 0 -23.5 10t-9.5 24v62h-291l-55 -81q-10 -15 -28 -15h-267q-21 0 -30.5 18t3.5 35l556 757q9 14 27 14h332q14 0 24 -10 t10 -24zM1783 641q0 -193 -125.5 -303t-324.5 -110h-270q-14 0 -24 10t-10 24v756q0 14 10 24t24 10h268q200 0 326 -109t126 -302zM1939 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-44.5 -108t-73.5 -102.5h-51q38 45 66.5 104.5t41.5 112t21 98t9 72.5l1 27q0 8 -0.5 22.5 t-7.5 60t-20 91.5t-41 111.5t-66 124.5h43q41 -47 72 -107t45.5 -111.5t23 -96t10.5 -70.5zM2123 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-45 -108t-74 -102.5h-51q38 45 66.5 104.5t41.5 112t21 98t9 72.5l1 27q0 8 -0.5 22.5t-7.5 60t-19.5 91.5t-40.5 111.5t-66 124.5 h43q41 -47 72 -107t45.5 -111.5t23 -96t10.5 -70.5zM2304 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-44.5 -108t-73.5 -102.5h-51q38 45 66 104.5t41 112t21 98t9 72.5l1 27q0 8 -0.5 22.5t-7.5 60t-19.5 91.5t-40.5 111.5t-66 124.5h43q41 -47 72 -107t45.5 -111.5t23 -96 t9.5 -70.5z" /> <glyph glyph-name="uniF2A0" unicode="" horiz-adv-x="1408" d="M617 -153q0 11 -13 58t-31 107t-20 69q-1 4 -5 26.5t-8.5 36t-13.5 21.5q-15 14 -51 14q-23 0 -70 -5.5t-71 -5.5q-34 0 -47 11q-6 5 -11 15.5t-7.5 20t-6.5 24t-5 18.5q-37 128 -37 255t37 255q1 4 5 18.5t6.5 24t7.5 20t11 15.5q13 11 47 11q24 0 71 -5.5t70 -5.5 q36 0 51 14q9 8 13.5 21.5t8.5 36t5 26.5q2 9 20 69t31 107t13 58q0 22 -43.5 52.5t-75.5 42.5q-20 8 -45 8q-34 0 -98 -18q-57 -17 -96.5 -40.5t-71 -66t-46 -70t-45.5 -94.5q-6 -12 -9 -19q-49 -107 -68 -216t-19 -244t19 -244t68 -216q56 -122 83 -161q63 -91 179 -127 l6 -2q64 -18 98 -18q25 0 45 8q32 12 75.5 42.5t43.5 52.5zM776 760q-26 0 -45 19t-19 45.5t19 45.5q37 37 37 90q0 52 -37 91q-19 19 -19 45t19 45t45 19t45 -19q75 -75 75 -181t-75 -181q-21 -19 -45 -19zM957 579q-27 0 -45 19q-19 19 -19 45t19 45q112 114 112 272 t-112 272q-19 19 -19 45t19 45t45 19t45 -19q150 -150 150 -362t-150 -362q-18 -19 -45 -19zM1138 398q-27 0 -45 19q-19 19 -19 45t19 45q90 91 138.5 208t48.5 245t-48.5 245t-138.5 208q-19 19 -19 45t19 45t45 19t45 -19q109 -109 167 -249t58 -294t-58 -294t-167 -249 q-18 -19 -45 -19z" /> <glyph glyph-name="uniF2A1" unicode="" horiz-adv-x="2176" d="M192 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM704 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM704 864q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1472 352 q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1472 864q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 864 q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 1376q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 192q0 -80 -56 -136 t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 1216q0 -80 -56 -136t-136 -56 t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM2176 192q0 -80 -56 -136t-136 -56t-136 56 t-56 136t56 136t136 56t136 -56t56 -136zM1664 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM2176 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136 t56 136t136 56t136 -56t56 -136zM2176 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136z" /> <glyph glyph-name="uniF2A2" unicode="" horiz-adv-x="1792" d="M128 -192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM320 0q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM365 365l256 -256l-90 -90l-256 256zM704 384q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45z M1411 704q0 -59 -11.5 -108.5t-37.5 -93.5t-44 -67.5t-53 -64.5q-31 -35 -45.5 -54t-33.5 -50t-26.5 -64t-7.5 -74q0 -159 -112.5 -271.5t-271.5 -112.5q-26 0 -45 19t-19 45t19 45t45 19q106 0 181 75t75 181q0 57 11.5 105.5t37 91t43.5 66.5t52 63q40 46 59.5 72 t37.5 74.5t18 103.5q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5zM896 576q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45 t45 19t45 -19t19 -45zM1184 704q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 93 -65.5 158.5t-158.5 65.5q-92 0 -158 -65.5t-66 -158.5q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 146 103 249t249 103t249 -103t103 -249zM1578 993q10 -25 -1 -49t-36 -34q-9 -4 -23 -4 q-19 0 -35.5 11t-23.5 30q-68 178 -224 295q-21 16 -25 42t12 47q17 21 43 25t47 -12q183 -137 266 -351zM1788 1074q9 -25 -1.5 -49t-35.5 -34q-11 -4 -23 -4q-44 0 -60 41q-92 238 -297 393q-22 16 -25.5 42t12.5 47q16 22 42 25.5t47 -12.5q235 -175 341 -449z" /> <glyph glyph-name="uniF2A3" unicode="" horiz-adv-x="2304" d="M1032 576q-59 2 -84 55q-17 34 -48 53.5t-68 19.5q-53 0 -90.5 -37.5t-37.5 -90.5q0 -56 36 -89l10 -8q34 -31 82 -31q37 0 68 19.5t48 53.5q25 53 84 55zM1600 704q0 56 -36 89l-10 8q-34 31 -82 31q-37 0 -68 -19.5t-48 -53.5q-25 -53 -84 -55q59 -2 84 -55 q17 -34 48 -53.5t68 -19.5q53 0 90.5 37.5t37.5 90.5zM1174 925q-17 -35 -55 -48t-73 4q-62 31 -134 31q-51 0 -99 -17q3 0 9.5 0.5t9.5 0.5q92 0 170.5 -50t118.5 -133q17 -36 3.5 -73.5t-49.5 -54.5q-18 -9 -39 -9q21 0 39 -9q36 -17 49.5 -54.5t-3.5 -73.5 q-40 -83 -118.5 -133t-170.5 -50h-6q-16 2 -44 4l-290 27l-239 -120q-14 -7 -29 -7q-40 0 -57 35l-160 320q-11 23 -4 47.5t29 37.5l209 119l148 267q17 155 91.5 291.5t195.5 236.5q31 25 70.5 21.5t64.5 -34.5t21.5 -70t-34.5 -65q-70 -59 -117 -128q123 84 267 101 q40 5 71.5 -19t35.5 -64q5 -40 -19 -71.5t-64 -35.5q-84 -10 -159 -55q46 10 99 10q115 0 218 -50q36 -18 49 -55.5t-5 -73.5zM2137 1085l160 -320q11 -23 4 -47.5t-29 -37.5l-209 -119l-148 -267q-17 -155 -91.5 -291.5t-195.5 -236.5q-26 -22 -61 -22q-45 0 -74 35 q-25 31 -21.5 70t34.5 65q70 59 117 128q-123 -84 -267 -101q-4 -1 -12 -1q-36 0 -63.5 24t-31.5 60q-5 40 19 71.5t64 35.5q84 10 159 55q-46 -10 -99 -10q-115 0 -218 50q-36 18 -49 55.5t5 73.5q17 35 55 48t73 -4q62 -31 134 -31q51 0 99 17q-3 0 -9.5 -0.5t-9.5 -0.5 q-92 0 -170.5 50t-118.5 133q-17 36 -3.5 73.5t49.5 54.5q18 9 39 9q-21 0 -39 9q-36 17 -49.5 54.5t3.5 73.5q40 83 118.5 133t170.5 50h6h1q14 -2 42 -4l291 -27l239 120q14 7 29 7q40 0 57 -35z" /> <glyph glyph-name="uniF2A4" unicode="" horiz-adv-x="1792" d="M1056 704q0 -26 19 -45t45 -19t45 19t19 45q0 146 -103 249t-249 103t-249 -103t-103 -249q0 -26 19 -45t45 -19t45 19t19 45q0 93 66 158.5t158 65.5t158 -65.5t66 -158.5zM835 1280q-117 0 -223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5q0 -26 19 -45t45 -19t45 19 t19 45q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -55 -18 -103.5t-37.5 -74.5t-59.5 -72q-34 -39 -52 -63t-43.5 -66.5t-37 -91t-11.5 -105.5q0 -106 -75 -181t-181 -75q-26 0 -45 -19t-19 -45t19 -45t45 -19q159 0 271.5 112.5t112.5 271.5q0 41 7.5 74 t26.5 64t33.5 50t45.5 54q35 41 53 64.5t44 67.5t37.5 93.5t11.5 108.5q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5zM591 561l226 -226l-579 -579q-12 -12 -29 -12t-29 12l-168 168q-12 12 -12 29t12 29zM1612 1524l168 -168q12 -12 12 -29t-12 -30l-233 -233 l-26 -25l-71 -71q-66 153 -195 258l91 91l207 207q13 12 30 12t29 -12z" /> <glyph glyph-name="uniF2A5" unicode="" d="M866 1021q0 -27 -13 -94q-11 -50 -31.5 -150t-30.5 -150q-2 -11 -4.5 -12.5t-13.5 -2.5q-20 -2 -31 -2q-58 0 -84 49.5t-26 113.5q0 88 35 174t103 124q28 14 51 14q28 0 36.5 -16.5t8.5 -47.5zM1352 597q0 14 -39 75.5t-52 66.5q-21 8 -34 8q-91 0 -226 -77l-2 2 q3 22 27.5 135t24.5 178q0 233 -242 233q-24 0 -68 -6q-94 -17 -168.5 -89.5t-111.5 -166.5t-37 -189q0 -146 80.5 -225t227.5 -79q25 0 25 -3t-1 -5q-4 -34 -26 -117q-14 -52 -51.5 -101t-82.5 -49q-42 0 -42 47q0 24 10.5 47.5t25 39.5t29.5 28.5t26 20t11 8.5q0 3 -7 10 q-24 22 -58.5 36.5t-65.5 14.5q-35 0 -63.5 -34t-41 -75t-12.5 -75q0 -88 51.5 -142t138.5 -54q82 0 155 53t117.5 126t65.5 153q6 22 15.5 66.5t14.5 66.5q3 12 14 18q118 60 227 60q48 0 127 -18q1 -1 4 -1q5 0 9.5 4.5t4.5 8.5zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="uniF2A6" unicode="" horiz-adv-x="1535" d="M744 1231q0 24 -2 38.5t-8.5 30t-21 23t-37.5 7.5q-39 0 -78 -23q-105 -58 -159 -190.5t-54 -269.5q0 -44 8.5 -85.5t26.5 -80.5t52.5 -62.5t81.5 -23.5q4 0 18 -0.5t20 0t16 3t15 8.5t7 16q16 77 48 231.5t48 231.5q19 91 19 146zM1498 575q0 -7 -7.5 -13.5t-15.5 -6.5 l-6 1q-22 3 -62 11t-72 12.5t-63 4.5q-167 0 -351 -93q-15 -8 -21 -27q-10 -36 -24.5 -105.5t-22.5 -100.5q-23 -91 -70 -179.5t-112.5 -164.5t-154.5 -123t-185 -47q-135 0 -214.5 83.5t-79.5 219.5q0 53 19.5 117t63 116.5t97.5 52.5q38 0 120 -33.5t83 -61.5 q0 -1 -16.5 -12.5t-39.5 -31t-46 -44.5t-39 -61t-16 -74q0 -33 16.5 -53t48.5 -20q45 0 85 31.5t66.5 78t48 105.5t32.5 107t16 90v9q0 2 -3.5 3.5t-8.5 1.5h-10t-10 -0.5t-6 -0.5q-227 0 -352 122.5t-125 348.5q0 108 34.5 221t96 210t156 167.5t204.5 89.5q52 9 106 9 q374 0 374 -360q0 -98 -38 -273t-43 -211l3 -3q101 57 182.5 88t167.5 31q22 0 53 -13q19 -7 80 -102.5t61 -116.5z" /> <glyph glyph-name="uniF2A7" unicode="" horiz-adv-x="1664" d="M831 863q32 0 59 -18l222 -148q61 -40 110 -97l146 -170q40 -46 29 -106l-72 -413q-6 -32 -29.5 -53.5t-55.5 -25.5l-527 -56l-352 -32h-9q-39 0 -67.5 28t-28.5 68q0 37 27 64t65 32l260 32h-448q-41 0 -69.5 30t-26.5 71q2 39 32 65t69 26l442 1l-521 64q-41 5 -66 37 t-19 73q6 35 34.5 57.5t65.5 22.5h10l481 -60l-351 94q-38 10 -62 41.5t-18 68.5q6 36 33 58.5t62 22.5q6 0 20 -2l448 -96l217 -37q1 0 3 -0.5t3 -0.5q23 0 30.5 23t-12.5 36l-186 125q-35 23 -42 63.5t18 73.5q27 38 76 38zM761 661l186 -125l-218 37l-5 2l-36 38 l-238 262q-1 1 -2.5 3.5t-2.5 3.5q-24 31 -18.5 70t37.5 64q31 23 68 17.5t64 -33.5l142 -147q-2 -1 -5 -3.5t-4 -4.5q-32 -45 -23 -99t55 -85zM1648 1115l15 -266q4 -73 -11 -147l-48 -219q-12 -59 -67 -87l-106 -54q2 62 -39 109l-146 170q-53 61 -117 103l-222 148 q-34 23 -76 23q-51 0 -88 -37l-235 312q-25 33 -18 73.5t41 63.5q33 22 71.5 14t62.5 -40l266 -352l-262 455q-21 35 -10.5 75t47.5 59q35 18 72.5 6t57.5 -46l241 -420l-136 337q-15 35 -4.5 74t44.5 56q37 19 76 6t56 -51l193 -415l101 -196q8 -15 23 -17.5t27 7.5t11 26 l-12 224q-2 41 26 71t69 31q39 0 67 -28.5t30 -67.5z" /> <glyph glyph-name="uniF2A8" unicode="" horiz-adv-x="1792" d="M335 180q-2 0 -6 2q-86 57 -168.5 145t-139.5 180q-21 30 -21 69q0 9 2 19t4 18t7 18t8.5 16t10.5 17t10 15t12 15.5t11 14.5q184 251 452 365q-110 198 -110 211q0 19 17 29q116 64 128 64q18 0 28 -16l124 -229q92 19 192 19q266 0 497.5 -137.5t378.5 -369.5 q20 -31 20 -69t-20 -69q-91 -142 -218.5 -253.5t-278.5 -175.5q110 -198 110 -211q0 -20 -17 -29q-116 -64 -127 -64q-19 0 -29 16l-124 229l-64 119l-444 820l7 7q-58 -24 -99 -47q3 -5 127 -234t243 -449t119 -223q0 -7 -9 -9q-13 -3 -72 -3q-57 0 -60 7l-456 841 q-39 -28 -82 -68q24 -43 214 -393.5t190 -354.5q0 -10 -11 -10q-14 0 -82.5 22t-72.5 28l-106 197l-224 413q-44 -53 -78 -106q2 -3 18 -25t23 -34l176 -327q0 -10 -10 -10zM1165 282l49 -91q273 111 450 385q-180 277 -459 389q67 -64 103 -148.5t36 -176.5 q0 -106 -47 -200.5t-132 -157.5zM848 896q0 -20 14 -34t34 -14q86 0 147 -61t61 -147q0 -20 14 -34t34 -14t34 14t14 34q0 126 -89 215t-215 89q-20 0 -34 -14t-14 -34zM1214 961l-9 4l7 -7z" /> <glyph glyph-name="uniF2A9" unicode="" horiz-adv-x="1280" d="M1050 430q0 -215 -147 -374q-148 -161 -378 -161q-232 0 -378 161q-147 159 -147 374q0 147 68 270.5t189 196.5t268 73q96 0 182 -31q-32 -62 -39 -126q-66 28 -143 28q-167 0 -280.5 -123t-113.5 -291q0 -170 112.5 -288.5t281.5 -118.5t281 118.5t112 288.5 q0 89 -32 166q66 13 123 49q41 -98 41 -212zM846 619q0 -192 -79.5 -345t-238.5 -253l-14 -1q-29 0 -62 5q83 32 146.5 102.5t99.5 154.5t58.5 189t30 192.5t7.5 178.5q0 69 -3 103q55 -160 55 -326zM791 947v-2q-73 214 -206 440q88 -59 142.5 -186.5t63.5 -251.5z M1035 744q-83 0 -160 75q218 120 290 247q19 37 21 56q-42 -94 -139.5 -166.5t-204.5 -97.5q-35 54 -35 113q0 37 17 79t43 68q46 44 157 74q59 16 106 58.5t74 100.5q74 -105 74 -253q0 -109 -24 -170q-32 -77 -88.5 -130.5t-130.5 -53.5z" /> <glyph glyph-name="uniF2AA" unicode="" d="M1050 495q0 78 -28 147q-41 -25 -85 -34q22 -50 22 -114q0 -117 -77 -198.5t-193 -81.5t-193.5 81.5t-77.5 198.5q0 115 78 199.5t193 84.5q53 0 98 -19q4 43 27 87q-60 21 -125 21q-154 0 -257.5 -108.5t-103.5 -263.5t103.5 -261t257.5 -106t257.5 106.5t103.5 260.5z M872 850q2 -24 2 -71q0 -63 -5 -123t-20.5 -132.5t-40.5 -130t-68.5 -106t-100.5 -70.5q21 -3 42 -3h10q219 139 219 411q0 116 -38 225zM872 850q-4 80 -44 171.5t-98 130.5q92 -156 142 -302zM1207 955q0 102 -51 174q-41 -86 -124 -109q-69 -19 -109 -53.5t-40 -99.5 q0 -40 24 -77q74 17 140.5 67t95.5 115q-4 -52 -74.5 -111.5t-138.5 -97.5q52 -52 110 -52q51 0 90 37t60 90q17 42 17 117zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" /> <glyph glyph-name="uniF2AB" unicode="" d="M1279 388q0 22 -22 27q-67 15 -118 59t-80 108q-7 19 -7 25q0 15 19.5 26t43 17t43 20.5t19.5 36.5q0 19 -18.5 31.5t-38.5 12.5q-12 0 -32 -8t-31 -8q-4 0 -12 2q5 95 5 114q0 79 -17 114q-36 78 -103 121.5t-152 43.5q-199 0 -275 -165q-17 -35 -17 -114q0 -19 5 -114 q-4 -2 -14 -2q-12 0 -32 7.5t-30 7.5q-21 0 -38.5 -12t-17.5 -32q0 -21 19.5 -35.5t43 -20.5t43 -17t19.5 -26q0 -6 -7 -25q-64 -138 -198 -167q-22 -5 -22 -27q0 -46 137 -68q2 -5 6 -26t11.5 -30.5t23.5 -9.5q12 0 37.5 4.5t39.5 4.5q35 0 67 -15t54 -32.5t57.5 -32.5 t76.5 -15q43 0 79 15t57.5 32.5t53.5 32.5t67 15q14 0 39.5 -4t38.5 -4q16 0 23 10t11 30t6 25q137 22 137 68zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" /> <glyph glyph-name="uniF2AC" unicode="" horiz-adv-x="1664" d="M848 1408q134 1 240.5 -68.5t163.5 -192.5q27 -58 27 -179q0 -47 -9 -191q14 -7 28 -7q18 0 51 13.5t51 13.5q29 0 56 -18t27 -46q0 -32 -31.5 -54t-69 -31.5t-69 -29t-31.5 -47.5q0 -15 12 -43q37 -82 102.5 -150t144.5 -101q28 -12 80 -23q28 -6 28 -35 q0 -70 -219 -103q-7 -11 -11 -39t-14 -46.5t-33 -18.5q-20 0 -62 6.5t-64 6.5q-37 0 -62 -5q-32 -5 -63 -22.5t-58 -38t-58 -40.5t-76 -33.5t-99 -13.5q-52 0 -96.5 13.5t-75 33.5t-57.5 40.5t-58 38t-62 22.5q-26 5 -63 5q-24 0 -65.5 -7.5t-58.5 -7.5q-25 0 -35 18.5 t-14 47.5t-11 40q-219 33 -219 103q0 29 28 35q52 11 80 23q78 32 144.5 101t102.5 150q12 28 12 43q0 28 -31.5 47.5t-69.5 29.5t-69.5 31.5t-31.5 52.5q0 27 26 45.5t55 18.5q15 0 48 -13t53 -13q18 0 32 7q-9 142 -9 190q0 122 27 180q64 137 172 198t264 63z" /> <glyph glyph-name="uniF2AD" unicode="" d="M1280 388q0 22 -22 27q-67 14 -118 58t-80 109q-7 14 -7 25q0 15 19.5 26t42.5 17t42.5 20.5t19.5 36.5q0 19 -18.5 31.5t-38.5 12.5q-11 0 -31 -8t-32 -8q-4 0 -12 2q5 63 5 115q0 78 -17 114q-36 78 -102.5 121.5t-152.5 43.5q-198 0 -275 -165q-18 -38 -18 -115 q0 -38 6 -114q-10 -2 -15 -2q-11 0 -31.5 8t-30.5 8q-20 0 -37.5 -12.5t-17.5 -32.5q0 -21 19.5 -35.5t42.5 -20.5t42.5 -17t19.5 -26q0 -11 -7 -25q-64 -138 -198 -167q-22 -5 -22 -27q0 -47 138 -69q2 -5 6 -26t11 -30.5t23 -9.5q13 0 38.5 5t38.5 5q35 0 67.5 -15 t54.5 -32.5t57.5 -32.5t76.5 -15q43 0 79 15t57.5 32.5t54 32.5t67.5 15q13 0 39 -4.5t39 -4.5q15 0 22.5 9.5t11.5 31t5 24.5q138 22 138 69zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960 q119 0 203.5 -84.5t84.5 -203.5z" /> <glyph glyph-name="uniF2AE" unicode="" horiz-adv-x="2304" d="M2304 1536q-69 -46 -125 -92t-89 -81t-59.5 -71.5t-37.5 -57.5t-22 -44.5t-14 -29.5q-10 -18 -35.5 -136.5t-48.5 -164.5q-15 -29 -50 -60.5t-67.5 -50.5t-72.5 -41t-48 -28q-47 -31 -151 -231q-341 14 -630 -158q-92 -53 -303 -179q47 16 86 31t55 22l15 7 q71 27 163 64.5t133.5 53.5t108 34.5t142.5 31.5q186 31 465 -7q1 0 10 -3q11 -6 14 -17t-3 -22l-194 -345q-15 -29 -47 -22q-128 24 -354 24q-146 0 -402 -44.5t-392 -46.5q-82 -1 -149 13t-107 37t-61 40t-33 34l-1 1v2q0 6 6 6q138 0 371 55q192 366 374.5 524t383.5 158 q5 0 14.5 -0.5t38 -5t55 -12t61.5 -24.5t63 -39.5t54 -59t40 -82.5l102 177q2 4 21 42.5t44.5 86.5t61 109.5t84 133.5t100.5 137q66 82 128 141.5t121.5 96.5t92.5 53.5t88 39.5z" /> <glyph glyph-name="uniF2B0" unicode="" d="M1322 640q0 -45 -5 -76l-236 14l224 -78q-19 -73 -58 -141l-214 103l177 -158q-44 -61 -107 -108l-157 178l103 -215q-61 -37 -140 -59l-79 228l14 -240q-38 -6 -76 -6t-76 6l14 238l-78 -226q-74 19 -140 59l103 215l-157 -178q-59 43 -108 108l178 158l-214 -104 q-39 69 -58 141l224 79l-237 -14q-5 42 -5 76q0 35 5 77l238 -14l-225 79q19 73 58 140l214 -104l-177 159q46 61 107 108l158 -178l-103 215q67 39 140 58l77 -224l-13 236q36 6 75 6q38 0 76 -6l-14 -237l78 225q74 -19 140 -59l-103 -214l158 178q61 -47 107 -108 l-177 -159l213 104q37 -62 58 -141l-224 -78l237 14q5 -31 5 -77zM1352 640q0 160 -78.5 295.5t-213 214t-292.5 78.5q-119 0 -227 -46.5t-186.5 -125t-124.5 -187.5t-46 -229q0 -119 46 -228t124.5 -187.5t186.5 -125t227 -46.5q158 0 292.5 78.5t213 214t78.5 294.5z M1425 1023v-766l-657 -383l-657 383v766l657 383zM768 -183l708 412v823l-708 411l-708 -411v-823zM1536 1088v-896l-768 -448l-768 448v896l768 448z" /> <glyph glyph-name="uniF2B1" unicode="" horiz-adv-x="1664" d="M339 1318h691l-26 -72h-665q-110 0 -188.5 -79t-78.5 -189v-771q0 -95 60.5 -169.5t153.5 -93.5q23 -5 98 -5v-72h-45q-140 0 -239.5 100t-99.5 240v771q0 140 99.5 240t239.5 100zM1190 1536h247l-482 -1294q-23 -61 -40.5 -103.5t-45 -98t-54 -93.5t-64.5 -78.5 t-79.5 -65t-95.5 -41t-116 -18.5v195q163 26 220 182q20 52 20 105q0 54 -20 106l-285 733h228l187 -585zM1664 978v-1111h-795q37 55 45 73h678v1038q0 85 -49.5 155t-129.5 99l25 67q101 -34 163.5 -123.5t62.5 -197.5z" /> <glyph glyph-name="uniF2B2" unicode="" horiz-adv-x="1792" d="M852 1227q0 -29 -17 -52.5t-45 -23.5t-45 23.5t-17 52.5t17 52.5t45 23.5t45 -23.5t17 -52.5zM688 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50 -21.5t-20 -51.5v-114q0 -30 20.5 -52t49.5 -22q30 0 50.5 22t20.5 52zM860 -149v114q0 30 -20 51.5t-50 21.5t-50.5 -21.5 t-20.5 -51.5v-114q0 -30 20.5 -52t50.5 -22q29 0 49.5 22t20.5 52zM1034 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50.5 -21.5t-20.5 -51.5v-114q0 -30 20.5 -52t50.5 -22t50.5 22t20.5 52zM1208 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50.5 -21.5t-20.5 -51.5v-114 q0 -30 20.5 -52t50.5 -22t50.5 22t20.5 52zM1476 535q-84 -160 -232 -259.5t-323 -99.5q-123 0 -229.5 51.5t-178.5 137t-113 197.5t-41 232q0 88 21 174q-104 -175 -104 -390q0 -162 65 -312t185 -251q30 57 91 57q56 0 86 -50q32 50 87 50q56 0 86 -50q32 50 87 50t87 -50 q30 50 86 50q28 0 52.5 -15.5t37.5 -40.5q112 94 177 231.5t73 287.5zM1326 564q0 75 -72 75q-17 0 -47 -6q-95 -19 -149 -19q-226 0 -226 243q0 86 30 204q-83 -127 -83 -275q0 -150 89 -260.5t235 -110.5q111 0 210 70q13 48 13 79zM884 1223q0 50 -32 89.5t-81 39.5 t-81 -39.5t-32 -89.5q0 -51 31.5 -90.5t81.5 -39.5t81.5 39.5t31.5 90.5zM1513 884q0 96 -37.5 179t-113 137t-173.5 54q-77 0 -149 -35t-127 -94q-48 -159 -48 -268q0 -104 45.5 -157t147.5 -53q53 0 142 19q36 6 53 6q51 0 77.5 -28t26.5 -80q0 -26 -4 -46 q75 68 117.5 165.5t42.5 200.5zM1792 667q0 -111 -33.5 -249.5t-93.5 -204.5q-58 -64 -195 -142.5t-228 -104.5l-4 -1v-114q0 -43 -29.5 -75t-72.5 -32q-56 0 -86 50q-32 -50 -87 -50t-87 50q-30 -50 -86 -50q-55 0 -87 50q-30 -50 -86 -50q-47 0 -75 33.5t-28 81.5 q-90 -68 -198 -68q-118 0 -211 80q54 1 106 20q-113 31 -182 127q32 -7 71 -7q89 0 164 46q-192 192 -240 306q-24 56 -24 160q0 57 9 125.5t31.5 146.5t55 141t86.5 105t120 42q59 0 81 -52q19 29 42 54q2 3 12 13t13 16q10 15 23 38t25 42t28 39q87 111 211.5 177 t260.5 66q35 0 62 -4q59 64 146 64q83 0 140 -57q5 -5 5 -12q0 -5 -6 -13.5t-12.5 -16t-16 -17l-10.5 -10.5q17 -6 36 -18t19 -24q0 -6 -16 -25q157 -138 197 -378q25 30 60 30q45 0 100 -49q90 -80 90 -279z" /> <glyph glyph-name="uniF2B3" unicode="" d="M917 631q0 33 -6 64h-362v-132h217q-12 -76 -74.5 -120.5t-142.5 -44.5q-99 0 -169 71.5t-70 170.5t70 170.5t169 71.5q93 0 153 -59l104 101q-108 100 -257 100q-160 0 -272 -112.5t-112 -271.5t112 -271.5t272 -112.5q165 0 266.5 105t101.5 270zM1262 585h109v110 h-109v110h-110v-110h-110v-110h110v-110h110v110zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> <glyph glyph-name="uniF2B4" unicode="" d="M1536 1024v-839q0 -48 -49 -62q-174 -52 -338 -52q-73 0 -215.5 29.5t-227.5 29.5q-164 0 -370 -48v-338h-160v1368q-63 25 -101 81t-38 124q0 91 64 155t155 64t155 -64t64 -155q0 -68 -38 -124t-101 -81v-68q190 44 343 44q99 0 198 -15q14 -2 111.5 -22.5t149.5 -20.5 q77 0 165 18q11 2 80 21t89 19q26 0 45 -19t19 -45z" /> <glyph glyph-name="uniF2B5" unicode="" horiz-adv-x="2304" d="M192 384q40 0 56 32t0 64t-56 32t-56 -32t0 -64t56 -32zM1665 442q-10 13 -38.5 50t-41.5 54t-38 49t-42.5 53t-40.5 47t-45 49l-125 -140q-83 -94 -208.5 -92t-205.5 98q-57 69 -56.5 158t58.5 157l177 206q-22 11 -51 16.5t-47.5 6t-56.5 -0.5t-49 -1q-92 0 -158 -66 l-158 -158h-155v-544q5 0 21 0.5t22 0t19.5 -2t20.5 -4.5t17.5 -8.5t18.5 -13.5l297 -292q115 -111 227 -111q78 0 125 47q57 -20 112.5 8t72.5 85q74 -6 127 44q20 18 36 45.5t14 50.5q10 -10 43 -10q43 0 77 21t49.5 53t12 71.5t-30.5 73.5zM1824 384h96v512h-93l-157 180 q-66 76 -169 76h-167q-89 0 -146 -67l-209 -243q-28 -33 -28 -75t27 -75q43 -51 110 -52t111 49l193 218q25 23 53.5 21.5t47 -27t8.5 -56.5q16 -19 56 -63t60 -68q29 -36 82.5 -105.5t64.5 -84.5q52 -66 60 -140zM2112 384q40 0 56 32t0 64t-56 32t-56 -32t0 -64t56 -32z M2304 960v-640q0 -26 -19 -45t-45 -19h-434q-27 -65 -82 -106.5t-125 -51.5q-33 -48 -80.5 -81.5t-102.5 -45.5q-42 -53 -104.5 -81.5t-128.5 -24.5q-60 -34 -126 -39.5t-127.5 14t-117 53.5t-103.5 81l-287 282h-358q-26 0 -45 19t-19 45v672q0 26 19 45t45 19h421 q14 14 47 48t47.5 48t44 40t50.5 37.5t51 25.5t62 19.5t68 5.5h117q99 0 181 -56q82 56 181 56h167q35 0 67 -6t56.5 -14.5t51.5 -26.5t44.5 -31t43 -39.5t39 -42t41 -48t41.5 -48.5h355q26 0 45 -19t19 -45z" /> <glyph glyph-name="uniF2B6" unicode="" horiz-adv-x="1792" d="M1792 882v-978q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v978q0 15 11 24q8 7 39 34.5t41.5 36t45.5 37.5t70 55.5t96 73t143.5 107t192.5 140.5q5 4 52.5 40t71.5 52.5t64 35t69 18.5t69 -18.5t65 -35.5t71 -52t52 -40q110 -80 192.5 -140.5t143.5 -107 t96 -73t70 -55.5t45.5 -37.5t41.5 -36t39 -34.5q11 -9 11 -24zM1228 297q263 191 345 252q11 8 12.5 20.5t-6.5 23.5l-38 52q-8 11 -21 12.5t-24 -6.5q-231 -169 -343 -250q-5 -3 -52 -39t-71.5 -52.5t-64.5 -35t-69 -18.5t-69 18.5t-64.5 35t-71.5 52.5t-52 39 q-186 134 -343 250q-11 8 -24 6.5t-21 -12.5l-38 -52q-8 -11 -6.5 -23.5t12.5 -20.5q82 -61 345 -252q10 -8 50 -38t65 -47t64 -39.5t77.5 -33.5t75.5 -11t75.5 11t79 34.5t64.5 39.5t65 47.5t48 36.5z" /> <glyph glyph-name="uniF2B7" unicode="" horiz-adv-x="1792" d="M1474 623l39 -51q8 -11 6.5 -23.5t-11.5 -20.5q-43 -34 -126.5 -98.5t-146.5 -113t-67 -51.5q-39 -32 -60 -48t-60.5 -41t-76.5 -36.5t-74 -11.5h-1h-1q-37 0 -74 11.5t-76 36.5t-61 41.5t-60 47.5q-5 4 -65 50.5t-143.5 111t-122.5 94.5q-11 8 -12.5 20.5t6.5 23.5 l37 52q8 11 21.5 13t24.5 -7q94 -73 306 -236q5 -4 43.5 -35t60.5 -46.5t56.5 -32.5t58.5 -17h1h1q24 0 58.5 17t56.5 32.5t60.5 46.5t43.5 35q258 198 313 242q11 8 24 6.5t21 -12.5zM1664 -96v928q-90 83 -159 139q-91 74 -389 304q-3 2 -43 35t-61 48t-56 32.5t-59 17.5 h-1h-1q-24 0 -59 -17.5t-56 -32.5t-61 -48t-43 -35q-215 -166 -315.5 -245.5t-129.5 -104t-82 -74.5q-14 -12 -21 -19v-928q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 832v-928q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v928q0 56 41 94 q123 114 350 290.5t233 181.5q36 30 59 47.5t61.5 42t76 36.5t74.5 12h1h1q37 0 74.5 -12t76 -36.5t61.5 -42t59 -47.5q43 -36 156 -122t226 -177t201 -173q41 -38 41 -94z" /> <glyph glyph-name="uniF2B8" unicode="" d="M330 1l202 -214l-34 236l-216 213zM556 -225l274 218l-11 245l-300 -215zM245 413l227 -213l-48 327l-245 204zM495 189l317 214l-14 324l-352 -200zM843 178l95 -80l-2 239l-103 79q0 -1 1 -8.5t0 -12t-5 -7.5l-78 -52l85 -70q7 -6 7 -88zM138 930l256 -200l-68 465 l-279 173zM1173 267l15 234l-230 -164l2 -240zM417 722l373 194l-19 441l-423 -163zM1270 357l20 233l-226 142l-2 -105l144 -95q6 -4 4 -9l-7 -119zM1461 496l30 222l-179 -128l-20 -228zM1273 329l-71 49l-8 -117q0 -5 -4 -8l-234 -187q-7 -5 -14 0l-98 83l7 -161 q0 -5 -4 -8l-293 -234q-4 -2 -6 -2q-8 2 -8 3l-228 242q-4 4 -59 277q-2 7 5 11l61 37q-94 86 -95 92l-72 351q-2 7 6 12l94 45q-133 100 -135 108l-96 466q-2 10 7 13l433 135q5 0 8 -1l317 -153q6 -4 6 -9l20 -463q0 -7 -6 -10l-118 -61l126 -85q5 -2 5 -8l5 -123l121 74 q5 4 11 0l84 -56l3 110q0 6 5 9l206 126q6 3 11 0l245 -135q4 -4 5 -7t-6.5 -60t-17.5 -124.5t-10 -70.5q0 -5 -4 -7l-191 -153q-6 -5 -13 0z" /> <glyph glyph-name="uniF2B9" unicode="" horiz-adv-x="1664" d="M1201 298q0 57 -5.5 107t-21 100.5t-39.5 86t-64 58t-91 22.5q-6 -4 -33.5 -20.5t-42.5 -24.5t-40.5 -20t-49 -17t-46.5 -5t-46.5 5t-49 17t-40.5 20t-42.5 24.5t-33.5 20.5q-51 0 -91 -22.5t-64 -58t-39.5 -86t-21 -100.5t-5.5 -107q0 -73 42 -121.5t103 -48.5h576 q61 0 103 48.5t42 121.5zM1028 892q0 108 -76.5 184t-183.5 76t-183.5 -76t-76.5 -184q0 -107 76.5 -183t183.5 -76t183.5 76t76.5 183zM1664 352v-192q0 -14 -9 -23t-23 -9h-96v-224q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v1472q0 66 47 113t113 47h1216 q66 0 113 -47t47 -113v-224h96q14 0 23 -9t9 -23v-192q0 -14 -9 -23t-23 -9h-96v-128h96q14 0 23 -9t9 -23v-192q0 -14 -9 -23t-23 -9h-96v-128h96q14 0 23 -9t9 -23z" /> <glyph glyph-name="uniF2BA" unicode="" horiz-adv-x="1664" d="M1028 892q0 -107 -76.5 -183t-183.5 -76t-183.5 76t-76.5 183q0 108 76.5 184t183.5 76t183.5 -76t76.5 -184zM980 672q46 0 82.5 -17t60 -47.5t39.5 -67t24 -81t11.5 -82.5t3.5 -79q0 -67 -39.5 -118.5t-105.5 -51.5h-576q-66 0 -105.5 51.5t-39.5 118.5q0 48 4.5 93.5 t18.5 98.5t36.5 91.5t63 64.5t93.5 26h5q7 -4 32 -19.5t35.5 -21t33 -17t37 -16t35 -9t39.5 -4.5t39.5 4.5t35 9t37 16t33 17t35.5 21t32 19.5zM1664 928q0 -13 -9.5 -22.5t-22.5 -9.5h-96v-128h96q13 0 22.5 -9.5t9.5 -22.5v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-96v-128h96 q13 0 22.5 -9.5t9.5 -22.5v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-96v-224q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v1472q0 66 47 113t113 47h1216q66 0 113 -47t47 -113v-224h96q13 0 22.5 -9.5t9.5 -22.5v-192zM1408 -96v1472q0 13 -9.5 22.5t-22.5 9.5h-1216 q-13 0 -22.5 -9.5t-9.5 -22.5v-1472q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5z" /> <glyph glyph-name="uniF2BB" unicode="" horiz-adv-x="2048" d="M1024 405q0 64 -9 117.5t-29.5 103t-60.5 78t-97 28.5q-6 -4 -30 -18t-37.5 -21.5t-35.5 -17.5t-43 -14.5t-42 -4.5t-42 4.5t-43 14.5t-35.5 17.5t-37.5 21.5t-30 18q-57 0 -97 -28.5t-60.5 -78t-29.5 -103t-9 -117.5t37 -106.5t91 -42.5h512q54 0 91 42.5t37 106.5z M867 925q0 94 -66.5 160.5t-160.5 66.5t-160.5 -66.5t-66.5 -160.5t66.5 -160.5t160.5 -66.5t160.5 66.5t66.5 160.5zM1792 416v64q0 14 -9 23t-23 9h-576q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h576q14 0 23 9t9 23zM1792 676v56q0 15 -10.5 25.5t-25.5 10.5h-568 q-15 0 -25.5 -10.5t-10.5 -25.5v-56q0 -15 10.5 -25.5t25.5 -10.5h568q15 0 25.5 10.5t10.5 25.5zM1792 928v64q0 14 -9 23t-23 9h-576q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h576q14 0 23 9t9 23zM2048 1248v-1216q0 -66 -47 -113t-113 -47h-352v96q0 14 -9 23t-23 9 h-64q-14 0 -23 -9t-9 -23v-96h-768v96q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-96h-352q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1728q66 0 113 -47t47 -113z" /> <glyph glyph-name="uniF2BC" unicode="" horiz-adv-x="2048" d="M1024 405q0 -64 -37 -106.5t-91 -42.5h-512q-54 0 -91 42.5t-37 106.5t9 117.5t29.5 103t60.5 78t97 28.5q6 -4 30 -18t37.5 -21.5t35.5 -17.5t43 -14.5t42 -4.5t42 4.5t43 14.5t35.5 17.5t37.5 21.5t30 18q57 0 97 -28.5t60.5 -78t29.5 -103t9 -117.5zM867 925 q0 -94 -66.5 -160.5t-160.5 -66.5t-160.5 66.5t-66.5 160.5t66.5 160.5t160.5 66.5t160.5 -66.5t66.5 -160.5zM1792 480v-64q0 -14 -9 -23t-23 -9h-576q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h576q14 0 23 -9t9 -23zM1792 732v-56q0 -15 -10.5 -25.5t-25.5 -10.5h-568 q-15 0 -25.5 10.5t-10.5 25.5v56q0 15 10.5 25.5t25.5 10.5h568q15 0 25.5 -10.5t10.5 -25.5zM1792 992v-64q0 -14 -9 -23t-23 -9h-576q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h576q14 0 23 -9t9 -23zM1920 32v1216q0 13 -9.5 22.5t-22.5 9.5h-1728q-13 0 -22.5 -9.5 t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h352v96q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-96h768v96q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-96h352q13 0 22.5 9.5t9.5 22.5zM2048 1248v-1216q0 -66 -47 -113t-113 -47h-1728q-66 0 -113 47t-47 113v1216q0 66 47 113 t113 47h1728q66 0 113 -47t47 -113z" /> <glyph glyph-name="uniF2BD" unicode="" horiz-adv-x="1792" d="M1523 197q-22 155 -87.5 257.5t-184.5 118.5q-67 -74 -159.5 -115.5t-195.5 -41.5t-195.5 41.5t-159.5 115.5q-119 -16 -184.5 -118.5t-87.5 -257.5q106 -150 271 -237.5t356 -87.5t356 87.5t271 237.5zM1280 896q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5 t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1792 640q0 -182 -71 -347.5t-190.5 -286t-285.5 -191.5t-349 -71q-182 0 -348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> <glyph glyph-name="uniF2BE" unicode="" horiz-adv-x="1792" d="M896 1536q182 0 348 -71t286 -191t191 -286t71 -348q0 -181 -70.5 -347t-190.5 -286t-286 -191.5t-349 -71.5t-349 71t-285.5 191.5t-190.5 286t-71 347.5t71 348t191 286t286 191t348 71zM1515 185q149 205 149 455q0 156 -61 298t-164 245t-245 164t-298 61t-298 -61 t-245 -164t-164 -245t-61 -298q0 -250 149 -455q66 327 306 327q131 -128 313 -128t313 128q240 0 306 -327zM1280 832q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5z" /> <glyph glyph-name="uniF2C0" unicode="" d="M1201 752q47 -14 89.5 -38t89 -73t79.5 -115.5t55 -172t22 -236.5q0 -154 -100 -263.5t-241 -109.5h-854q-141 0 -241 109.5t-100 263.5q0 131 22 236.5t55 172t79.5 115.5t89 73t89.5 38q-79 125 -79 272q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5 t198.5 -40.5t163.5 -109.5t109.5 -163.5t40.5 -198.5q0 -147 -79 -272zM768 1408q-159 0 -271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5zM1195 -128q88 0 150.5 71.5t62.5 173.5q0 239 -78.5 377t-225.5 145 q-145 -127 -336 -127t-336 127q-147 -7 -225.5 -145t-78.5 -377q0 -102 62.5 -173.5t150.5 -71.5h854z" /> <glyph glyph-name="uniF2C1" unicode="" horiz-adv-x="1280" d="M1024 278q0 -64 -37 -107t-91 -43h-512q-54 0 -91 43t-37 107t9 118t29.5 104t61 78.5t96.5 28.5q80 -75 188 -75t188 75q56 0 96.5 -28.5t61 -78.5t29.5 -104t9 -118zM870 797q0 -94 -67.5 -160.5t-162.5 -66.5t-162.5 66.5t-67.5 160.5t67.5 160.5t162.5 66.5 t162.5 -66.5t67.5 -160.5zM1152 -96v1376h-1024v-1376q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1280 1376v-1472q0 -66 -47 -113t-113 -47h-960q-66 0 -113 47t-47 113v1472q0 66 47 113t113 47h352v-96q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v96h352 q66 0 113 -47t47 -113z" /> <glyph glyph-name="uniF2C2" unicode="" horiz-adv-x="2048" d="M896 324q0 54 -7.5 100.5t-24.5 90t-51 68.5t-81 25q-64 -64 -156 -64t-156 64q-47 0 -81 -25t-51 -68.5t-24.5 -90t-7.5 -100.5q0 -55 31.5 -93.5t75.5 -38.5h426q44 0 75.5 38.5t31.5 93.5zM768 768q0 80 -56 136t-136 56t-136 -56t-56 -136t56 -136t136 -56t136 56 t56 136zM1792 288v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1408 544v64q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1792 544v64q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23 v-64q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1792 800v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM128 1152h1792v96q0 14 -9 23t-23 9h-1728q-14 0 -23 -9t-9 -23v-96zM2048 1248v-1216q0 -66 -47 -113t-113 -47h-1728 q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1728q66 0 113 -47t47 -113z" /> <glyph glyph-name="uniF2C3" unicode="" horiz-adv-x="2048" d="M896 324q0 -55 -31.5 -93.5t-75.5 -38.5h-426q-44 0 -75.5 38.5t-31.5 93.5q0 54 7.5 100.5t24.5 90t51 68.5t81 25q64 -64 156 -64t156 64q47 0 81 -25t51 -68.5t24.5 -90t7.5 -100.5zM768 768q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136z M1792 352v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM1408 608v-64q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h320q14 0 23 -9t9 -23zM1792 608v-64q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v64 q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 864v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM1920 32v1120h-1792v-1120q0 -13 9.5 -22.5t22.5 -9.5h1728q13 0 22.5 9.5t9.5 22.5zM2048 1248v-1216q0 -66 -47 -113t-113 -47 h-1728q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1728q66 0 113 -47t47 -113z" /> <glyph glyph-name="uniF2C4" unicode="" horiz-adv-x="1792" d="M1255 749q0 318 -105 474.5t-330 156.5q-222 0 -326 -157t-104 -474q0 -316 104 -471.5t326 -155.5q74 0 131 17q-22 43 -39 73t-44 65t-53.5 56.5t-63 36t-77.5 14.5q-46 0 -79 -16l-49 97q105 91 276 91q132 0 215.5 -54t150.5 -155q67 149 67 402zM1645 117h117 q3 -27 -2 -67t-26.5 -95t-58 -100.5t-107 -78t-162.5 -32.5q-71 0 -130.5 19t-105.5 56t-79 78t-66 96q-97 -27 -205 -27q-150 0 -292.5 58t-253 158.5t-178 249t-67.5 317.5q0 170 67.5 319.5t178.5 250.5t253.5 159t291.5 58q121 0 238.5 -36t217 -106t176 -164.5 t119.5 -219t43 -261.5q0 -190 -80.5 -347.5t-218.5 -264.5q47 -70 93.5 -106.5t104.5 -36.5q61 0 94 37.5t38 85.5z" /> <glyph glyph-name="uniF2C5" unicode="" horiz-adv-x="2304" d="M453 -101q0 -21 -16 -37.5t-37 -16.5q-1 0 -13 3q-63 15 -162 140q-225 284 -225 676q0 341 213 614q39 51 95 103.5t94 52.5q19 0 35 -13.5t16 -32.5q0 -27 -63 -90q-98 -102 -147 -184q-119 -199 -119 -449q0 -281 123 -491q50 -85 136 -173q2 -3 14.5 -16t19.5 -21 t17 -20.5t14.5 -23.5t4.5 -21zM1796 33q0 -29 -17.5 -48.5t-46.5 -19.5h-1081q-26 0 -45 19t-19 45q0 29 17.5 48.5t46.5 19.5h1081q26 0 45 -19t19 -45zM1581 644q0 -134 -67 -233q-25 -38 -69.5 -78.5t-83.5 -60.5q-16 -10 -27 -10q-7 0 -15 6t-8 12q0 9 19 30t42 46 t42 67.5t19 88.5q0 76 -35 130q-29 42 -46 42q-3 0 -3 -5q0 -12 7.5 -35.5t7.5 -36.5q0 -22 -21.5 -35t-44.5 -13q-66 0 -66 76q0 15 1.5 44t1.5 44q0 25 -10 46q-13 25 -42 53.5t-51 28.5q-5 0 -7 -0.5t-3.5 -2.5t-1.5 -6q0 -2 16 -26t16 -54q0 -37 -19 -68t-46 -54 t-53.5 -46t-45.5 -54t-19 -68q0 -98 42 -160q29 -43 79 -63q16 -5 17 -10q1 -2 1 -5q0 -16 -18 -16q-6 0 -33 11q-119 43 -195 139.5t-76 218.5q0 55 24.5 115.5t60 115t70.5 108.5t59.5 113.5t24.5 111.5q0 53 -25 94q-29 48 -56 64q-19 9 -19 21q0 20 41 20q50 0 110 -29 q41 -19 71 -44.5t49.5 -51t33.5 -62.5t22 -69t16 -80q0 -1 3 -17.5t4.5 -25t5.5 -25t9 -27t11 -21.5t14.5 -16.5t18.5 -5.5q23 0 37 14t14 37q0 25 -20 67t-20 52t10 10q27 0 93 -70q72 -76 102.5 -156t30.5 -186zM2304 615q0 -274 -138 -503q-19 -32 -48 -72t-68 -86.5 t-81 -77t-74 -30.5q-16 0 -31 15.5t-15 31.5q0 15 29 50.5t68.5 77t48.5 52.5q183 230 183 531q0 131 -20.5 235t-72.5 211q-58 119 -163 228q-2 3 -13 13.5t-16.5 16.5t-15 17.5t-15 20t-9.5 18.5t-4 19q0 19 16 35.5t35 16.5q70 0 196 -169q98 -131 146 -273t60 -314 q2 -42 2 -64z" /> <glyph glyph-name="uniF2C6" unicode="" horiz-adv-x="1792" d="M1189 229l147 693q9 44 -10.5 63t-51.5 7l-864 -333q-29 -11 -39.5 -25t-2.5 -26.5t32 -19.5l221 -69l513 323q21 14 32 6q7 -5 -4 -15l-415 -375v0v0l-16 -228q23 0 45 22l108 104l224 -165q64 -36 81 38zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71 t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> <glyph glyph-name="uniF2C7" unicode="" horiz-adv-x="1024" d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 60 35 110t93 71v907h128v-907q58 -21 93 -71t35 -110zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5 t93.5 226.5zM896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192 v128h192z" /> <glyph glyph-name="uniF2C8" unicode="" horiz-adv-x="1024" d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 60 35 110t93 71v651h128v-651q58 -21 93 -71t35 -110zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5 t93.5 226.5zM896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192 v128h192z" /> <glyph glyph-name="uniF2C9" unicode="" horiz-adv-x="1024" d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 60 35 110t93 71v395h128v-395q58 -21 93 -71t35 -110zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5 t93.5 226.5zM896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192 v128h192z" /> <glyph glyph-name="uniF2CA" unicode="" horiz-adv-x="1024" d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 60 35 110t93 71v139h128v-139q58 -21 93 -71t35 -110zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5 t93.5 226.5zM896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192 v128h192z" /> <glyph glyph-name="uniF2CB" unicode="" horiz-adv-x="1024" d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 79 56 135.5t136 56.5t136 -56.5t56 -135.5zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5t93.5 226.5z M896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192v128h192z" /> <glyph glyph-name="uniF2CC" unicode="" horiz-adv-x="1920" d="M1433 1287q10 -10 10 -23t-10 -23l-626 -626q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l44 44q-72 91 -81.5 207t46.5 215q-74 71 -176 71q-106 0 -181 -75t-75 -181v-1280h-256v1280q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5q106 0 201 -41 t166 -115q94 39 197 24.5t185 -79.5l44 44q10 10 23 10t23 -10zM1344 1024q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1600 896q-26 0 -45 19t-19 45t19 45t45 19t45 -19t19 -45t-19 -45t-45 -19zM1856 1024q26 0 45 -19t19 -45t-19 -45t-45 -19 t-45 19t-19 45t19 45t45 19zM1216 896q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1408 832q0 26 19 45t45 19t45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45zM1728 896q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1088 768 q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1344 640q-26 0 -45 19t-19 45t19 45t45 19t45 -19t19 -45t-19 -45t-45 -19zM1600 768q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1216 512q-26 0 -45 19t-19 45t19 45t45 19t45 -19 t19 -45t-19 -45t-45 -19zM1472 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1088 512q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1344 512q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1216 384 q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1088 256q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19z" /> <glyph glyph-name="uniF2CD" unicode="" horiz-adv-x="1792" d="M1664 448v-192q0 -169 -128 -286v-194q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v118q-63 -22 -128 -22h-768q-65 0 -128 22v-110q0 -17 -9.5 -28.5t-22.5 -11.5h-64q-13 0 -22.5 11.5t-9.5 28.5v186q-128 117 -128 286v192h1536zM704 864q0 -14 -9 -23t-23 -9t-23 9 t-9 23t9 23t23 9t23 -9t9 -23zM768 928q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM704 992q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM832 992q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM768 1056q0 -14 -9 -23t-23 -9t-23 9 t-9 23t9 23t23 9t23 -9t9 -23zM704 1120q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM1792 608v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v640q0 106 75 181t181 75q108 0 184 -78q46 19 98 12t93 -39l22 22q11 11 22 0l42 -42 q11 -11 0 -22l-314 -314q-11 -11 -22 0l-42 42q-11 11 0 22l22 22q-36 46 -40.5 104t23.5 108q-37 35 -88 35q-53 0 -90.5 -37.5t-37.5 -90.5v-640h1504q14 0 23 -9t9 -23zM896 1056q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM832 1120q0 -14 -9 -23t-23 -9 t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM768 1184q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM960 1120q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM896 1184q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM832 1248q0 -14 -9 -23 t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM1024 1184q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM960 1248q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM1088 1248q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23z" /> <glyph glyph-name="uniF2CE" unicode="" d="M994 344q0 -86 -17 -197q-31 -215 -55 -313q-22 -90 -152 -90t-152 90q-24 98 -55 313q-17 110 -17 197q0 168 224 168t224 -168zM1536 768q0 -240 -134 -434t-350 -280q-8 -3 -15 3t-6 15q7 48 10 66q4 32 6 47q1 9 9 12q159 81 255.5 234t96.5 337q0 180 -91 330.5 t-247 234.5t-337 74q-124 -7 -237 -61t-193.5 -140.5t-128 -202t-46.5 -240.5q1 -184 99 -336.5t257 -231.5q7 -3 9 -12q3 -21 6 -45q1 -9 5 -32.5t6 -35.5q1 -9 -6.5 -15t-15.5 -2q-148 58 -261 169.5t-173.5 264t-52.5 319.5q7 143 66 273.5t154.5 227t225 157.5t272.5 70 q164 10 315.5 -46.5t261 -160.5t175 -250.5t65.5 -308.5zM994 800q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5zM1282 768q0 -122 -53.5 -228.5t-146.5 -177.5q-8 -6 -16 -2t-10 14q-6 52 -29 92q-7 10 3 20 q58 54 91 127t33 155q0 111 -58.5 204t-157.5 141.5t-212 36.5q-133 -15 -229 -113t-109 -231q-10 -92 23.5 -176t98.5 -144q10 -10 3 -20q-24 -41 -29 -93q-2 -9 -10 -13t-16 2q-95 74 -148.5 183t-51.5 234q3 131 69 244t177 181.5t241 74.5q144 7 268 -60t196.5 -187.5 t72.5 -263.5z" /> <glyph glyph-name="uniF2D0" unicode="" horiz-adv-x="1792" d="M256 128h1280v768h-1280v-768zM1792 1248v-1216q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" /> <glyph glyph-name="uniF2D1" unicode="" horiz-adv-x="1792" d="M1792 224v-192q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" /> <glyph glyph-name="uniF2D2" unicode="" horiz-adv-x="2048" d="M256 0h768v512h-768v-512zM1280 512h512v768h-768v-256h96q66 0 113 -47t47 -113v-352zM2048 1376v-960q0 -66 -47 -113t-113 -47h-608v-352q0 -66 -47 -113t-113 -47h-960q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h608v352q0 66 47 113t113 47h960q66 0 113 -47 t47 -113z" /> <glyph glyph-name="uniF2D3" unicode="" horiz-adv-x="1792" d="M1175 215l146 146q10 10 10 23t-10 23l-233 233l233 233q10 10 10 23t-10 23l-146 146q-10 10 -23 10t-23 -10l-233 -233l-233 233q-10 10 -23 10t-23 -10l-146 -146q-10 -10 -10 -23t10 -23l233 -233l-233 -233q-10 -10 -10 -23t10 -23l146 -146q10 -10 23 -10t23 10 l233 233l233 -233q10 -10 23 -10t23 10zM1792 1248v-1216q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" /> <glyph glyph-name="uniF2D4" unicode="" horiz-adv-x="1792" d="M1257 425l-146 -146q-10 -10 -23 -10t-23 10l-169 169l-169 -169q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l169 169l-169 169q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l169 -169l169 169q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 l-169 -169l169 -169q10 -10 10 -23t-10 -23zM256 128h1280v1024h-1280v-1024zM1792 1248v-1216q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" /> <glyph glyph-name="uniF2D5" unicode="" horiz-adv-x="1792" d="M1070 358l306 564h-654l-306 -564h654zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> <glyph glyph-name="uniF2D6" unicode="" horiz-adv-x="1794" d="M1291 1060q-15 17 -35 8.5t-26 -28.5t5 -38q14 -17 40 -14.5t34 20.5t-18 52zM895 814q-8 -8 -19.5 -8t-18.5 8q-8 8 -8 19t8 18q7 8 18.5 8t19.5 -8q7 -7 7 -18t-7 -19zM1060 740l-35 -35q-12 -13 -29.5 -13t-30.5 13l-38 38q-12 13 -12 30t12 30l35 35q12 12 29.5 12 t30.5 -12l38 -39q12 -12 12 -29.5t-12 -29.5zM951 870q-7 -8 -18.5 -8t-19.5 8q-7 8 -7 19t7 19q8 8 19 8t19 -8t8 -19t-8 -19zM1354 968q-34 -64 -107.5 -85.5t-127.5 16.5q-38 28 -61 66.5t-21 87.5t39 92t75.5 53t70.5 -5t70 -51q2 -2 13 -12.5t14.5 -13.5t13 -13.5 t12.5 -15.5t10 -15.5t8.5 -18t4 -18.5t1 -21t-5 -22t-9.5 -24zM1555 486q3 20 -8.5 34.5t-27.5 21.5t-33 17t-23 20q-40 71 -84 98.5t-113 11.5q19 13 40 18.5t33 4.5l12 -1q2 45 -34 90q6 20 6.5 40.5t-2.5 30.5l-3 10q43 24 71 65t34 91q10 84 -43 150.5t-137 76.5 q-60 7 -114 -18.5t-82 -74.5q-30 -51 -33.5 -101t14.5 -87t43.5 -64t56.5 -42q-45 4 -88 36t-57 88q-28 108 32 222q-16 21 -29 32q-50 0 -89 -19q19 24 42 37t36 14l13 1q0 50 -13 78q-10 21 -32.5 28.5t-47 -3.5t-37.5 -40q2 4 4 7q-7 -28 -6.5 -75.5t19 -117t48.5 -122.5 q-25 -14 -47 -36q-35 -16 -85.5 -70.5t-84.5 -101.5l-33 -46q-90 -34 -181 -125.5t-75 -162.5q1 -16 11 -27q-15 -12 -30 -30q-21 -25 -21 -54t21.5 -40t63.5 6q41 19 77 49.5t55 60.5q-2 2 -6.5 5t-20.5 7.5t-33 3.5q23 5 51 12.5t40 10t27.5 6t26 4t23.5 0.5q14 -7 22 34 q7 37 7 90q0 102 -40 150q106 -103 101 -219q-1 -29 -15 -50t-27 -27l-13 -6q-4 -7 -19 -32t-26 -45.5t-26.5 -52t-25 -61t-17 -63t-6.5 -66.5t10 -63q-35 54 -37 80q-22 -24 -34.5 -39t-33.5 -42t-30.5 -46t-16.5 -41t-0.5 -38t25.5 -27q45 -25 144 64t190.5 221.5 t122.5 228.5q86 52 145 115.5t86 119.5q47 -93 154 -178q104 -83 167 -80q39 2 46 43zM1794 640q0 -182 -71 -348t-191 -286t-286.5 -191t-348.5 -71t-348.5 71t-286.5 191t-191 286t-71 348t71 348t191 286t286.5 191t348.5 71t348.5 -71t286.5 -191t191 -286t71 -348z" /> <glyph glyph-name="uniF2D7" unicode="" d="M518 1353v-655q103 -1 191.5 1.5t125.5 5.5l37 3q68 2 90.5 24.5t39.5 94.5l33 142h103l-14 -322l7 -319h-103l-29 127q-15 68 -45 93t-84 26q-87 8 -352 8v-556q0 -78 43.5 -115.5t133.5 -37.5h357q35 0 59.5 2t55 7.5t54 18t48.5 32t46 50.5t39 73l93 216h89 q-6 -37 -31.5 -252t-30.5 -276q-146 5 -263.5 8t-162.5 4h-44h-628l-376 -12v102l127 25q67 13 91.5 37t25.5 79l8 643q3 402 -8 645q-2 61 -25.5 84t-91.5 36l-127 24v102l376 -12h702q139 0 374 27q-6 -68 -14 -194.5t-12 -219.5l-5 -92h-93l-32 124q-31 121 -74 179.5 t-113 58.5h-548q-28 0 -35.5 -8.5t-7.5 -30.5z" /> <glyph glyph-name="uniF2D8" unicode="" d="M922 739v-182q0 -4 0.5 -15t0 -15l-1.5 -12t-3.5 -11.5t-6.5 -7.5t-11 -5.5t-16 -1.5v309q9 0 16 -1t11 -5t6.5 -5.5t3.5 -9.5t1 -10.5v-13.5v-14zM1238 643v-121q0 -1 0.5 -12.5t0 -15.5t-2.5 -11.5t-7.5 -10.5t-13.5 -3q-9 0 -14 9q-4 10 -4 165v7v8.5v9t1.5 8.5l3.5 7 t5 5.5t8 1.5q6 0 10 -1.5t6.5 -4.5t4 -6t2 -8.5t0.5 -8v-9.5v-9zM180 407h122v472h-122v-472zM614 407h106v472h-159l-28 -221q-20 148 -32 221h-158v-472h107v312l45 -312h76l43 319v-319zM1039 712q0 67 -5 90q-3 16 -11 28.5t-17 20.5t-25 14t-26.5 8.5t-31 4t-29 1.5 h-29.5h-12h-91v-472h56q169 -1 197 24.5t25 180.5q-1 62 -1 100zM1356 515v133q0 29 -2 45t-9.5 33.5t-24.5 25t-46 7.5q-46 0 -77 -34v154h-117v-472h110l7 30q30 -36 77 -36q50 0 66 30.5t16 83.5zM1536 1248v-1216q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113 v1216q0 66 47 113t113 47h1216q66 0 113 -47t47 -113z" /> <glyph glyph-name="uniF2D9" unicode="" horiz-adv-x="2176" d="M1143 -197q-6 1 -11 4q-13 8 -36 23t-86 65t-116.5 104.5t-112 140t-89.5 172.5q-17 3 -175 37q66 -213 235 -362t391 -184zM502 409l168 -28q-25 76 -41 167.5t-19 145.5l-4 53q-84 -82 -121 -224q5 -65 17 -114zM612 1018q-43 -64 -77 -148q44 46 74 68zM2049 584 q0 161 -62 307t-167.5 252t-250.5 168.5t-304 62.5q-147 0 -281 -52.5t-240 -148.5q-30 -58 -45 -160q60 51 143 83.5t158.5 43t143 13.5t108.5 -1l40 -3q33 -1 53 -15.5t24.5 -33t6.5 -37t-1 -28.5q-126 11 -227.5 0.5t-183 -43.5t-142.5 -71.5t-131 -98.5 q4 -36 11.5 -92.5t35.5 -178t62 -179.5q123 -6 247.5 14.5t214.5 53.5t162.5 67t109.5 59l37 24q22 16 39.5 20.5t30.5 -5t17 -34.5q14 -97 -39 -121q-208 -97 -467 -134q-135 -20 -317 -16q41 -96 110 -176.5t137 -127t130.5 -79t101.5 -43.5l39 -12q143 -23 263 15 q195 99 314 289t119 418zM2123 621q-14 -135 -40 -212q-70 -208 -181.5 -346.5t-318.5 -253.5q-48 -33 -82 -44q-72 -26 -163 -16q-36 -3 -73 -3q-283 0 -504.5 173t-295.5 442q-1 0 -4 0.5t-5 0.5q-6 -50 2.5 -112.5t26 -115t36 -98t31.5 -71.5l14 -26q8 -12 54 -82 q-71 38 -124.5 106.5t-78.5 140t-39.5 137t-17.5 107.5l-2 42q-5 2 -33.5 12.5t-48.5 18t-53 20.5t-57.5 25t-50 25.5t-42.5 27t-25 25.5q19 -10 50.5 -25.5t113 -45.5t145.5 -38l2 32q11 149 94 290q41 202 176 365q28 115 81 214q15 28 32 45t49 32q158 74 303.5 104 t302 11t306.5 -97q220 -115 333 -336t87 -474z" /> <glyph glyph-name="uniF2DA" unicode="" horiz-adv-x="1792" d="M1341 752q29 44 -6.5 129.5t-121.5 142.5q-58 39 -125.5 53.5t-118 4.5t-68.5 -37q-12 -23 -4.5 -28t42.5 -10q23 -3 38.5 -5t44.5 -9.5t56 -17.5q36 -13 67.5 -31.5t53 -37t40 -38.5t30.5 -38t22 -34.5t16.5 -28.5t12 -18.5t10.5 -6t11 9.5zM1704 178 q-52 -127 -148.5 -220t-214.5 -141.5t-253 -60.5t-266 13.5t-251 91t-210 161.5t-141.5 235.5t-46.5 303.5q1 41 8.5 84.5t12.5 64t24 80.5t23 73q-51 -208 1 -397t173 -318t291 -206t346 -83t349 74.5t289 244.5q20 27 18 14q0 -4 -4 -14zM1465 627q0 -104 -40.5 -199 t-108.5 -164t-162 -109.5t-198 -40.5t-198 40.5t-162 109.5t-108.5 164t-40.5 199t40.5 199t108.5 164t162 109.5t198 40.5t198 -40.5t162 -109.5t108.5 -164t40.5 -199zM1752 915q-65 147 -180.5 251t-253 153.5t-292 53.5t-301 -36.5t-275.5 -129t-220 -211.5t-131 -297 t-10 -373q-49 161 -51.5 311.5t35.5 272.5t109 227t165.5 180.5t207 126t232 71t242.5 9t236 -54t216 -124.5t178 -197q33 -50 62 -121t31 -112zM1690 573q12 244 -136.5 416t-396.5 240q-8 0 -10 5t24 8q125 -4 230 -50t173 -120t116 -168.5t58.5 -199t-1 -208 t-61.5 -197.5t-122.5 -167t-185 -117.5t-248.5 -46.5q108 30 201.5 80t174 123t129.5 176.5t55 225.5z" /> <glyph glyph-name="uniF2DB" unicode="" d="M192 256v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16q0 16 16 16h112zM192 512v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16q0 16 16 16h112zM192 768v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16 q0 16 16 16h112zM192 1024v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16q0 16 16 16h112zM192 1280v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16q0 16 16 16h112zM1280 1440v-1472q0 -40 -28 -68t-68 -28h-832q-40 0 -68 28 t-28 68v1472q0 40 28 68t68 28h832q40 0 68 -28t28 -68zM1536 208v-32q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16h48q16 0 16 -16zM1536 464v-32q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16h48q16 0 16 -16zM1536 720v-32 q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16h48q16 0 16 -16zM1536 976v-32q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16h48q16 0 16 -16zM1536 1232v-32q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16 h48q16 0 16 -16z" /> <glyph glyph-name="uniF2DC" unicode="" horiz-adv-x="1664" d="M1566 419l-167 -33l186 -107q23 -13 29.5 -38.5t-6.5 -48.5q-14 -23 -39 -29.5t-48 6.5l-186 106l55 -160q13 -38 -12 -63.5t-60.5 -20.5t-48.5 42l-102 300l-271 156v-313l208 -238q16 -18 17 -39t-11 -36.5t-28.5 -25t-37 -5.5t-36.5 22l-112 128v-214q0 -26 -19 -45 t-45 -19t-45 19t-19 45v214l-112 -128q-16 -18 -36.5 -22t-37 5.5t-28.5 25t-11 36.5t17 39l208 238v313l-271 -156l-102 -300q-13 -37 -48.5 -42t-60.5 20.5t-12 63.5l55 160l-186 -106q-23 -13 -48 -6.5t-39 29.5q-13 23 -6.5 48.5t29.5 38.5l186 107l-167 33 q-29 6 -42 29t-8.5 46.5t25.5 40t50 10.5l310 -62l271 157l-271 157l-310 -62q-4 -1 -13 -1q-27 0 -44 18t-19 40t11 43t40 26l167 33l-186 107q-23 13 -29.5 38.5t6.5 48.5t39 30t48 -7l186 -106l-55 160q-13 38 12 63.5t60.5 20.5t48.5 -42l102 -300l271 -156v313 l-208 238q-16 18 -17 39t11 36.5t28.5 25t37 5.5t36.5 -22l112 -128v214q0 26 19 45t45 19t45 -19t19 -45v-214l112 128q16 18 36.5 22t37 -5.5t28.5 -25t11 -36.5t-17 -39l-208 -238v-313l271 156l102 300q13 37 48.5 42t60.5 -20.5t12 -63.5l-55 -160l186 106 q23 13 48 6.5t39 -29.5q13 -23 6.5 -48.5t-29.5 -38.5l-186 -107l167 -33q27 -5 40 -26t11 -43t-19 -40t-44 -18q-9 0 -13 1l-310 62l-271 -157l271 -157l310 62q29 6 50 -10.5t25.5 -40t-8.5 -46.5t-42 -29z" /> <glyph glyph-name="uniF2DD" unicode="" horiz-adv-x="1792" d="M1473 607q7 118 -33 226.5t-113 189t-177 131t-221 57.5q-116 7 -225.5 -32t-192 -110.5t-135 -175t-59.5 -220.5q-7 -118 33 -226.5t113 -189t177.5 -131t221.5 -57.5q155 -9 293 59t224 195.5t94 283.5zM1792 1536l-349 -348q120 -117 180.5 -272t50.5 -321 q-11 -183 -102 -339t-241 -255.5t-332 -124.5l-999 -132l347 347q-120 116 -180.5 271.5t-50.5 321.5q11 184 102 340t241.5 255.5t332.5 124.5q167 22 500 66t500 66z" /> <glyph glyph-name="uniF2DE" unicode="" horiz-adv-x="1792" d="M948 508l163 -329h-51l-175 350l-171 -350h-49l179 374l-78 33l21 49l240 -102l-21 -50zM563 1100l304 -130l-130 -304l-304 130zM907 915l240 -103l-103 -239l-239 102zM1188 765l191 -81l-82 -190l-190 81zM1680 640q0 159 -62 304t-167.5 250.5t-250.5 167.5t-304 62 t-304 -62t-250.5 -167.5t-167.5 -250.5t-62 -304t62 -304t167.5 -250.5t250.5 -167.5t304 -62t304 62t250.5 167.5t167.5 250.5t62 304zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71 t286 -191t191 -286t71 -348z" /> <glyph glyph-name="uniF2E0" unicode="" horiz-adv-x="1920" d="M1334 302q-4 24 -27.5 34t-49.5 10.5t-48.5 12.5t-25.5 38q-5 47 33 139.5t75 181t32 127.5q-14 101 -117 103q-45 1 -75 -16l-3 -2l-5 -2.5t-4.5 -2t-5 -2t-5 -0.5t-6 1.5t-6 3.5t-6.5 5q-3 2 -9 8.5t-9 9t-8.5 7.5t-9.5 7.5t-9.5 5.5t-11 4.5t-11.5 2.5q-30 5 -48 -3 t-45 -31q-1 -1 -9 -8.5t-12.5 -11t-15 -10t-16.5 -5.5t-17 3q-54 27 -84 40q-41 18 -94 -5t-76 -65q-16 -28 -41 -98.5t-43.5 -132.5t-40 -134t-21.5 -73q-22 -69 18.5 -119t110.5 -46q30 2 50.5 15t38.5 46q7 13 79 199.5t77 194.5q6 11 21.5 18t29.5 0q27 -15 21 -53 q-2 -18 -51 -139.5t-50 -132.5q-6 -38 19.5 -56.5t60.5 -7t55 49.5q4 8 45.5 92t81.5 163.5t46 88.5q20 29 41 28q29 0 25 -38q-2 -16 -65.5 -147.5t-70.5 -159.5q-12 -53 13 -103t74 -74q17 -9 51 -15.5t71.5 -8t62.5 14t20 48.5zM383 86q3 -15 -5 -27.5t-23 -15.5 q-14 -3 -26.5 5t-15.5 23q-3 14 5 27t22 16t27 -5t16 -23zM953 -177q12 -17 8.5 -37.5t-20.5 -32.5t-37.5 -8t-32.5 21q-11 17 -7.5 37.5t20.5 32.5t37.5 8t31.5 -21zM177 635q-18 -27 -49.5 -33t-57.5 13q-26 18 -32 50t12 58q18 27 49.5 33t57.5 -12q26 -19 32 -50.5 t-12 -58.5zM1467 -42q19 -28 13 -61.5t-34 -52.5t-60.5 -13t-51.5 34t-13 61t33 53q28 19 60.5 13t52.5 -34zM1579 562q69 -113 42.5 -244.5t-134.5 -207.5q-90 -63 -199 -60q-20 -80 -84.5 -127t-143.5 -44.5t-140 57.5q-12 -9 -13 -10q-103 -71 -225 -48.5t-193 126.5 q-50 73 -53 164q-83 14 -142.5 70.5t-80.5 128t-2 152t81 138.5q-36 60 -38 128t24.5 125t79.5 98.5t121 50.5q32 85 99 148t146.5 91.5t168 17t159.5 -66.5q72 21 140 17.5t128.5 -36t104.5 -80t67.5 -115t17.5 -140.5q52 -16 87 -57t45.5 -89t-5.5 -99.5t-58 -87.5z M455 1222q14 -20 9.5 -44.5t-24.5 -38.5q-19 -14 -43.5 -9.5t-37.5 24.5q-14 20 -9.5 44.5t24.5 38.5q19 14 43.5 9.5t37.5 -24.5zM614 1503q4 -16 -5 -30.5t-26 -18.5t-31 5.5t-18 26.5q-3 17 6.5 31t25.5 18q17 4 31 -5.5t17 -26.5zM1800 555q4 -20 -6.5 -37t-30.5 -21 q-19 -4 -36 6.5t-21 30.5t6.5 37t30.5 22q20 4 36.5 -7.5t20.5 -30.5zM1136 1448q16 -27 8.5 -58.5t-35.5 -47.5q-27 -16 -57.5 -8.5t-46.5 34.5q-16 28 -8.5 59t34.5 48t58 9t47 -36zM1882 792q4 -15 -4 -27.5t-23 -16.5q-15 -3 -27.5 5.5t-15.5 22.5q-3 15 5 28t23 16 q14 3 26.5 -5t15.5 -23zM1691 1033q15 -22 10.5 -49t-26.5 -43q-22 -15 -49 -10t-42 27t-10 49t27 43t48.5 11t41.5 -28z" /> <glyph glyph-name="uniF2E1" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="uniF2E2" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="uniF2E3" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="uniF2E4" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="uniF2E5" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="uniF2E6" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="uniF2E7" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="_698" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="uniF2E9" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="uniF2EA" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="uniF2EB" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="uniF2EC" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="uniF2ED" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="uniF2EE" unicode="" horiz-adv-x="1792" /> <glyph glyph-name="lessequal" unicode="" horiz-adv-x="1792" /> </font> </defs></svg>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -0,0 +1,4 @@html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block}
-
-
html/_static/doctools.js (new)
-
@@ -0,0 +1,156 @@/* * doctools.js * ~~~~~~~~~~~ * * Base JavaScript utilities for all Sphinx HTML documentation. * * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ "use strict"; const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ "TEXTAREA", "INPUT", "SELECT", "BUTTON", ]); const _ready = (callback) => { if (document.readyState !== "loading") { callback(); } else { document.addEventListener("DOMContentLoaded", callback); } }; /** * Small JavaScript module for the documentation. */ const Documentation = { init: () => { Documentation.initDomainIndexTable(); Documentation.initOnKeyListeners(); }, /** * i18n support */ TRANSLATIONS: {}, PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), LOCALE: "unknown", // gettext and ngettext don't access this so that the functions // can safely bound to a different name (_ = Documentation.gettext) gettext: (string) => { const translated = Documentation.TRANSLATIONS[string]; switch (typeof translated) { case "undefined": return string; // no translation case "string": return translated; // translation exists default: return translated[0]; // (singular, plural) translation tuple exists } }, ngettext: (singular, plural, n) => { const translated = Documentation.TRANSLATIONS[singular]; if (typeof translated !== "undefined") return translated[Documentation.PLURAL_EXPR(n)]; return n === 1 ? singular : plural; }, addTranslations: (catalog) => { Object.assign(Documentation.TRANSLATIONS, catalog.messages); Documentation.PLURAL_EXPR = new Function( "n", `return (${catalog.plural_expr})` ); Documentation.LOCALE = catalog.locale; }, /** * helper function to focus on search bar */ focusSearchBar: () => { document.querySelectorAll("input[name=q]")[0]?.focus(); }, /** * Initialise the domain index toggle buttons */ initDomainIndexTable: () => { const toggler = (el) => { const idNumber = el.id.substr(7); const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); if (el.src.substr(-9) === "minus.png") { el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; toggledRows.forEach((el) => (el.style.display = "none")); } else { el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; toggledRows.forEach((el) => (el.style.display = "")); } }; const togglerElements = document.querySelectorAll("img.toggler"); togglerElements.forEach((el) => el.addEventListener("click", (event) => toggler(event.currentTarget)) ); togglerElements.forEach((el) => (el.style.display = "")); if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); }, initOnKeyListeners: () => { // only install a listener if it is really needed if ( !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS ) return; document.addEventListener("keydown", (event) => { // bail for input elements if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; // bail with special keys if (event.altKey || event.ctrlKey || event.metaKey) return; if (!event.shiftKey) { switch (event.key) { case "ArrowLeft": if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; const prevLink = document.querySelector('link[rel="prev"]'); if (prevLink && prevLink.href) { window.location.href = prevLink.href; event.preventDefault(); } break; case "ArrowRight": if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; const nextLink = document.querySelector('link[rel="next"]'); if (nextLink && nextLink.href) { window.location.href = nextLink.href; event.preventDefault(); } break; } } // some keyboard layouts may need Shift to get / switch (event.key) { case "/": if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; Documentation.focusSearchBar(); event.preventDefault(); } }); }, }; // quick alias for translations const _ = Documentation.gettext; _ready(Documentation.init);
-
-
-
@@ -0,0 +1,14 @@var DOCUMENTATION_OPTIONS = { URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), VERSION: '0.1', LANGUAGE: 'en', COLLAPSE_INDEX: false, BUILDER: 'html', FILE_SUFFIX: '.html', LINK_SUFFIX: '.html', HAS_SOURCE: true, SOURCELINK_SUFFIX: '.txt', NAVIGATION_WITH_KEYS: false, SHOW_SEARCH_SUMMARY: true, ENABLE_SEARCH_SHORTCUTS: true, };
-
-
html/_static/favicon.ico (new)
-
html/_static/file.png (new)
-
html/_static/jquery.js (new)
-
@@ -0,0 +1,2 @@/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:y}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),j=function(e,t){return e===t&&(l=!0),0},D={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",F=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",B=new RegExp(M+"+","g"),$=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="<a id='"+S+"'></a><select id='"+S+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!=C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&D.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(j),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(B," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),x="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[k,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[k,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[S]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace($,"$1"));return s[S]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[k,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[S]||(e[S]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===k&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[S]&&(v=Ce(v)),y&&!y[S]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace($,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace($," ")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=A[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[S]?i.push(a):o.push(a);(a=A(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=k+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(k=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(k=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=S.split("").sort(j).join("")===S,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);S.find=d,S.expr=d.selectors,S.expr[":"]=S.expr.pseudos,S.uniqueSort=S.unique=d.uniqueSort,S.text=d.getText,S.isXMLDoc=d.isXML,S.contains=d.contains,S.escapeSelector=d.escape;var h=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&S(e).is(n))break;r.push(e)}return r},T=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},k=S.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var N=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1<i.call(n,e)!==r}):S.filter(n,e,r)}S.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?S.find.matchesSelector(r,e)?[r]:[]:S.find.matches(e,S.grep(t,function(e){return 1===e.nodeType}))},S.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(S(e).filter(function(){for(t=0;t<r;t++)if(S.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)S.find(e,i[t],n);return 1<r?S.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&k.test(e)?S(e):e||[],!1).length}});var D,q=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(S.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&S(e);if(!k.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&S.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?S.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(S(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(S.uniqueSort(S.merge(this.get(),S(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),S.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return h(e,"parentNode")},parentsUntil:function(e,t,n){return h(e,"parentNode",n)},next:function(e){return O(e,"nextSibling")},prev:function(e){return O(e,"previousSibling")},nextAll:function(e){return h(e,"nextSibling")},prevAll:function(e){return h(e,"previousSibling")},nextUntil:function(e,t,n){return h(e,"nextSibling",n)},prevUntil:function(e,t,n){return h(e,"previousSibling",n)},siblings:function(e){return T((e.parentNode||{}).firstChild,e)},children:function(e){return T(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(A(e,"template")&&(e=e.content||e),S.merge([],e.childNodes))}},function(r,i){S.fn[r]=function(e,t){var n=S.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=S.filter(t,n)),1<this.length&&(H[r]||S.uniqueSort(n),L.test(r)&&n.reverse()),this.pushStack(n)}});var P=/[^\x20\t\r\n\f]+/g;function R(e){return e}function M(e){throw e}function I(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}S.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},S.each(e.match(P)||[],function(e,t){n[t]=!0}),n):S.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){S.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return S.each(arguments,function(e,t){var n;while(-1<(n=S.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<S.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},S.extend({Deferred:function(e){var o=[["notify","progress",S.Callbacks("memory"),S.Callbacks("memory"),2],["resolve","done",S.Callbacks("once memory"),S.Callbacks("once memory"),0,"resolved"],["reject","fail",S.Callbacks("once memory"),S.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return S.Deferred(function(r){S.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,R,s),l(u,o,M,s)):(u++,t.call(e,l(u,o,R,s),l(u,o,M,s),l(u,o,R,o.notifyWith))):(a!==R&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){S.Deferred.exceptionHook&&S.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==M&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(S.Deferred.getStackHook&&(t.stackTrace=S.Deferred.getStackHook()),C.setTimeout(t))}}return S.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:R,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:R)),o[2][3].add(l(0,e,m(n)?n:M))}).promise()},promise:function(e){return null!=e?S.extend(e,a):a}},s={};return S.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=S.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(I(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)I(i[t],a(t),o.reject);return o.promise()}});var W=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;S.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&W.test(e.name)&&C.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},S.readyException=function(e){C.setTimeout(function(){throw e})};var F=S.Deferred();function B(){E.removeEventListener("DOMContentLoaded",B),C.removeEventListener("load",B),S.ready()}S.fn.ready=function(e){return F.then(e)["catch"](function(e){S.readyException(e)}),this},S.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--S.readyWait:S.isReady)||(S.isReady=!0)!==e&&0<--S.readyWait||F.resolveWith(E,[S])}}),S.ready.then=F.then,"complete"===E.readyState||"loading"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(S.ready):(E.addEventListener("DOMContentLoaded",B),C.addEventListener("load",B));var $=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===w(n))for(s in i=!0,n)$(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(S(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},_=/^-ms-/,z=/-([a-z])/g;function U(e,t){return t.toUpperCase()}function X(e){return e.replace(_,"ms-").replace(z,U)}var V=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function G(){this.expando=S.expando+G.uid++}G.uid=1,G.prototype={cache:function(e){var t=e[this.expando];return t||(t={},V(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[X(t)]=n;else for(r in t)i[X(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][X(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(X):(t=X(t))in r?[t]:t.match(P)||[]).length;while(n--)delete r[t[n]]}(void 0===t||S.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!S.isEmptyObject(t)}};var Y=new G,Q=new G,J=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,K=/[A-Z]/g;function Z(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(K,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:J.test(i)?JSON.parse(i):i)}catch(e){}Q.set(e,t,n)}else n=void 0;return n}S.extend({hasData:function(e){return Q.hasData(e)||Y.hasData(e)},data:function(e,t,n){return Q.access(e,t,n)},removeData:function(e,t){Q.remove(e,t)},_data:function(e,t,n){return Y.access(e,t,n)},_removeData:function(e,t){Y.remove(e,t)}}),S.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=Q.get(o),1===o.nodeType&&!Y.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=X(r.slice(5)),Z(o,r,i[r]));Y.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){Q.set(this,n)}):$(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=Q.get(o,n))?t:void 0!==(t=Z(o,n))?t:void 0;this.each(function(){Q.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){Q.remove(this,e)})}}),S.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Y.get(e,t),n&&(!r||Array.isArray(n)?r=Y.access(e,t,S.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=S.queue(e,t),r=n.length,i=n.shift(),o=S._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){S.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Y.get(e,n)||Y.access(e,n,{empty:S.Callbacks("once memory").add(function(){Y.remove(e,[t+"queue",n])})})}}),S.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?S.queue(this[0],t):void 0===n?this:this.each(function(){var e=S.queue(this,t,n);S._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&S.dequeue(this,t)})},dequeue:function(e){return this.each(function(){S.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=S.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=Y.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var ee=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,te=new RegExp("^(?:([+-])=|)("+ee+")([a-z%]*)$","i"),ne=["Top","Right","Bottom","Left"],re=E.documentElement,ie=function(e){return S.contains(e.ownerDocument,e)},oe={composed:!0};re.getRootNode&&(ie=function(e){return S.contains(e.ownerDocument,e)||e.getRootNode(oe)===e.ownerDocument});var ae=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&ie(e)&&"none"===S.css(e,"display")};function se(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return S.css(e,t,"")},u=s(),l=n&&n[3]||(S.cssNumber[t]?"":"px"),c=e.nodeType&&(S.cssNumber[t]||"px"!==l&&+u)&&te.exec(S.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)S.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,S.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ue={};function le(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Y.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ae(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ue[s])||(o=a.body.appendChild(a.createElement(s)),u=S.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ue[s]=u)))):"none"!==n&&(l[c]="none",Y.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}S.fn.extend({show:function(){return le(this,!0)},hide:function(){return le(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?S(this).show():S(this).hide()})}});var ce,fe,pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="<option></option>",y.option=!!ce.lastChild;var ge={thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Y.set(e[n],"globalEval",!t||Y.get(t[n],"globalEval"))}ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td,y.option||(ge.optgroup=ge.option=[1,"<select multiple='multiple'>","</select>"]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===w(o))S.merge(p,o.nodeType?[o]:o);else if(me.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+S.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;S.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<S.inArray(o,r))i&&i.push(o);else if(l=ie(o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}var be=/^([^.]*)(?:\.(.+)|)/;function we(){return!0}function Te(){return!1}function Ce(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ee(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ee(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Te;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return S().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=S.guid++)),e.each(function(){S.event.add(this,t,i,r,n)})}function Se(e,i,o){o?(Y.set(e,i,!1),S.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Y.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(S.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Y.set(this,i,r),t=o(this,i),this[i](),r!==(n=Y.get(this,i))||t?Y.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n&&n.value}else r.length&&(Y.set(this,i,{value:S.event.trigger(S.extend(r[0],S.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,i)&&S.event.add(e,i,we)}S.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.get(t);if(V(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&S.find.matchesSelector(re,i),n.guid||(n.guid=S.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof S&&S.event.triggered!==e.type?S.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(P)||[""]).length;while(l--)d=g=(s=be.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=S.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=S.event.special[d]||{},c=S.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&S.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),S.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(P)||[""]).length;while(l--)if(d=g=(s=be.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=S.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||S.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)S.event.remove(e,d+t[l],n,r,!0);S.isEmptyObject(u)&&Y.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=S.event.fix(e),l=(Y.get(this,"events")||Object.create(null))[u.type]||[],c=S.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=S.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((S.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<S(i,this).index(l):S.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(S.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[S.expando]?e:new S.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Se(t,"click",we),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Se(t,"click"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,"input")&&Y.get(t,"click")||A(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},S.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},S.Event=function(e,t){if(!(this instanceof S.Event))return new S.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?we:Te,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&S.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[S.expando]=!0},S.Event.prototype={constructor:S.Event,isDefaultPrevented:Te,isPropagationStopped:Te,isImmediatePropagationStopped:Te,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=we,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=we,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=we,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},S.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:!0},S.event.addProp),S.each({focus:"focusin",blur:"focusout"},function(e,t){S.event.special[e]={setup:function(){return Se(this,e,Ce),!1},trigger:function(){return Se(this,e),!0},_default:function(){return!0},delegateType:t}}),S.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){S.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||S.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),S.fn.extend({on:function(e,t,n,r){return Ee(this,e,t,n,r)},one:function(e,t,n,r){return Ee(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,S(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=Te),this.each(function(){S.event.remove(this,e,n,t)})}});var ke=/<script|<style|<link/i,Ae=/checked\s*(?:[^=]|=\s*.checked.)/i,Ne=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)S.event.add(t,i,s[i][n]);Q.hasData(e)&&(o=Q.access(e),a=S.extend({},o),Q.set(t,a))}}function He(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&"string"==typeof d&&!y.checkClone&&Ae.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),He(t,r,i,o)});if(f&&(t=(e=xe(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=S.map(ve(e,"script"),De)).length;c<f;c++)u=e,c!==p&&(u=S.clone(u,!0,!0),s&&S.merge(a,ve(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,S.map(a,qe),c=0;c<s;c++)u=a[c],he.test(u.type||"")&&!Y.access(u,"globalEval")&&S.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?S._evalUrl&&!u.noModule&&S._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):b(u.textContent.replace(Ne,""),u,l))}return n}function Oe(e,t,n){for(var r,i=t?S.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||S.cleanData(ve(r)),r.parentNode&&(n&&ie(r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}S.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=ie(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||S.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Le(o[r],a[r]);else Le(e,c);return 0<(a=ve(c,"script")).length&&ye(a,!f&&ve(e,"script")),c},cleanData:function(e){for(var t,n,r,i=S.event.special,o=0;void 0!==(n=e[o]);o++)if(V(n)){if(t=n[Y.expando]){if(t.events)for(r in t.events)i[r]?S.event.remove(n,r):S.removeEvent(n,r,t.handle);n[Y.expando]=void 0}n[Q.expando]&&(n[Q.expando]=void 0)}}}),S.fn.extend({detach:function(e){return Oe(this,e,!0)},remove:function(e){return Oe(this,e)},text:function(e){return $(this,function(e){return void 0===e?S.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return He(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||je(this,e).appendChild(e)})},prepend:function(){return He(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=je(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return He(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return He(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(S.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return S.clone(this,e,t)})},html:function(e){return $(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!ke.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=S.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(S.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return He(this,arguments,function(e){var t=this.parentNode;S.inArray(this,n)<0&&(S.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),S.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){S.fn[e]=function(e){for(var t,n=[],r=S(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),S(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var Pe=new RegExp("^("+ee+")(?!px)[a-z%]+$","i"),Re=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},Me=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Ie=new RegExp(ne.join("|"),"i");function We(e,t,n){var r,i,o,a,s=e.style;return(n=n||Re(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||ie(e)||(a=S.style(e,t)),!y.pixelBoxStyles()&&Pe.test(a)&&Ie.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function Fe(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",l.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",re.appendChild(u).appendChild(l);var e=C.getComputedStyle(l);n="1%"!==e.top,s=12===t(e.marginLeft),l.style.right="60%",o=36===t(e.right),r=36===t(e.width),l.style.position="absolute",i=12===t(l.offsetWidth/3),re.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=E.createElement("div"),l=E.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===l.style.backgroundClip,S.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=E.createElement("table"),t=E.createElement("tr"),n=E.createElement("div"),e.style.cssText="position:absolute;left:-11111px;border-collapse:separate",t.style.cssText="border:1px solid",t.style.height="1px",n.style.height="9px",n.style.display="block",re.appendChild(e).appendChild(t).appendChild(n),r=C.getComputedStyle(t),a=parseInt(r.height,10)+parseInt(r.borderTopWidth,10)+parseInt(r.borderBottomWidth,10)===t.offsetHeight,re.removeChild(e)),a}}))}();var Be=["Webkit","Moz","ms"],$e=E.createElement("div").style,_e={};function ze(e){var t=S.cssProps[e]||_e[e];return t||(e in $e?e:_e[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Be.length;while(n--)if((e=Be[n]+t)in $e)return e}(e)||e)}var Ue=/^(none|table(?!-c[ea]).+)/,Xe=/^--/,Ve={position:"absolute",visibility:"hidden",display:"block"},Ge={letterSpacing:"0",fontWeight:"400"};function Ye(e,t,n){var r=te.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Qe(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=S.css(e,n+ne[a],!0,i)),r?("content"===n&&(u-=S.css(e,"padding"+ne[a],!0,i)),"margin"!==n&&(u-=S.css(e,"border"+ne[a]+"Width",!0,i))):(u+=S.css(e,"padding"+ne[a],!0,i),"padding"!==n?u+=S.css(e,"border"+ne[a]+"Width",!0,i):s+=S.css(e,"border"+ne[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function Je(e,t,n){var r=Re(e),i=(!y.boxSizingReliable()||n)&&"border-box"===S.css(e,"boxSizing",!1,r),o=i,a=We(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(Pe.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||!y.reliableTrDimensions()&&A(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===S.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===S.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Qe(e,t,n||(i?"border":"content"),o,r,a)+"px"}function Ke(e,t,n,r,i){return new Ke.prototype.init(e,t,n,r,i)}S.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=We(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=X(t),u=Xe.test(t),l=e.style;if(u||(t=ze(s)),a=S.cssHooks[t]||S.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=te.exec(n))&&i[1]&&(n=se(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(S.cssNumber[s]?"":"px")),y.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=X(t);return Xe.test(t)||(t=ze(s)),(a=S.cssHooks[t]||S.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=We(e,t,r)),"normal"===i&&t in Ge&&(i=Ge[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),S.each(["height","width"],function(e,u){S.cssHooks[u]={get:function(e,t,n){if(t)return!Ue.test(S.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?Je(e,u,n):Me(e,Ve,function(){return Je(e,u,n)})},set:function(e,t,n){var r,i=Re(e),o=!y.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===S.css(e,"boxSizing",!1,i),s=n?Qe(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-Qe(e,u,"border",!1,i)-.5)),s&&(r=te.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=S.css(e,u)),Ye(0,t,s)}}}),S.cssHooks.marginLeft=Fe(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(We(e,"marginLeft"))||e.getBoundingClientRect().left-Me(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),S.each({margin:"",padding:"",border:"Width"},function(i,o){S.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+ne[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(S.cssHooks[i+o].set=Ye)}),S.fn.extend({css:function(e,t){return $(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Re(e),i=t.length;a<i;a++)o[t[a]]=S.css(e,t[a],!1,r);return o}return void 0!==n?S.style(e,t,n):S.css(e,t)},e,t,1<arguments.length)}}),((S.Tween=Ke).prototype={constructor:Ke,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||S.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(S.cssNumber[n]?"":"px")},cur:function(){var e=Ke.propHooks[this.prop];return e&&e.get?e.get(this):Ke.propHooks._default.get(this)},run:function(e){var t,n=Ke.propHooks[this.prop];return this.options.duration?this.pos=t=S.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Ke.propHooks._default.set(this),this}}).init.prototype=Ke.prototype,(Ke.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=S.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){S.fx.step[e.prop]?S.fx.step[e.prop](e):1!==e.elem.nodeType||!S.cssHooks[e.prop]&&null==e.elem.style[ze(e.prop)]?e.elem[e.prop]=e.now:S.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=Ke.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},S.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},S.fx=Ke.prototype.init,S.fx.step={};var Ze,et,tt,nt,rt=/^(?:toggle|show|hide)$/,it=/queueHooks$/;function ot(){et&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(ot):C.setTimeout(ot,S.fx.interval),S.fx.tick())}function at(){return C.setTimeout(function(){Ze=void 0}),Ze=Date.now()}function st(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=ne[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function ut(e,t,n){for(var r,i=(lt.tweeners[t]||[]).concat(lt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function lt(o,e,t){var n,a,r=0,i=lt.prefilters.length,s=S.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=Ze||at(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:S.extend({},e),opts:S.extend(!0,{specialEasing:{},easing:S.easing._default},t),originalProperties:e,originalOptions:t,startTime:Ze||at(),duration:t.duration,tweens:[],createTween:function(e,t){var n=S.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=X(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=S.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=lt.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(S._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return S.map(c,ut,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),S.fx.timer(S.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}S.Animation=S.extend(lt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return se(n.elem,e,te.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(P);for(var n,r=0,i=e.length;r<i;r++)n=e[r],lt.tweeners[n]=lt.tweeners[n]||[],lt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ae(e),v=Y.get(e,"fxshow");for(r in n.queue||(null==(a=S._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,S.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],rt.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||S.style(e,r)}if((u=!S.isEmptyObject(t))||!S.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Y.get(e,"display")),"none"===(c=S.css(e,"display"))&&(l?c=l:(le([e],!0),l=e.style.display||l,c=S.css(e,"display"),le([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===S.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=Y.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&le([e],!0),p.done(function(){for(r in g||le([e]),Y.remove(e,"fxshow"),d)S.style(e,r,d[r])})),u=ut(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?lt.prefilters.unshift(e):lt.prefilters.push(e)}}),S.speed=function(e,t,n){var r=e&&"object"==typeof e?S.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return S.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in S.fx.speeds?r.duration=S.fx.speeds[r.duration]:r.duration=S.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&S.dequeue(this,r.queue)},r},S.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ae).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=S.isEmptyObject(t),o=S.speed(e,n,r),a=function(){var e=lt(this,S.extend({},t),o);(i||Y.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=S.timers,r=Y.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&it.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||S.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=Y.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=S.timers,o=n?n.length:0;for(t.finish=!0,S.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),S.each(["toggle","show","hide"],function(e,r){var i=S.fn[r];S.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(st(r,!0),e,t,n)}}),S.each({slideDown:st("show"),slideUp:st("hide"),slideToggle:st("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){S.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),S.timers=[],S.fx.tick=function(){var e,t=0,n=S.timers;for(Ze=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||S.fx.stop(),Ze=void 0},S.fx.timer=function(e){S.timers.push(e),S.fx.start()},S.fx.interval=13,S.fx.start=function(){et||(et=!0,ot())},S.fx.stop=function(){et=null},S.fx.speeds={slow:600,fast:200,_default:400},S.fn.delay=function(r,e){return r=S.fx&&S.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},tt=E.createElement("input"),nt=E.createElement("select").appendChild(E.createElement("option")),tt.type="checkbox",y.checkOn=""!==tt.value,y.optSelected=nt.selected,(tt=E.createElement("input")).value="t",tt.type="radio",y.radioValue="t"===tt.value;var ct,ft=S.expr.attrHandle;S.fn.extend({attr:function(e,t){return $(this,S.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){S.removeAttr(this,e)})}}),S.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?S.prop(e,t,n):(1===o&&S.isXMLDoc(e)||(i=S.attrHooks[t.toLowerCase()]||(S.expr.match.bool.test(t)?ct:void 0)),void 0!==n?null===n?void S.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=S.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(P);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),ct={set:function(e,t,n){return!1===t?S.removeAttr(e,n):e.setAttribute(n,n),n}},S.each(S.expr.match.bool.source.match(/\w+/g),function(e,t){var a=ft[t]||S.find.attr;ft[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=ft[o],ft[o]=r,r=null!=a(e,t,n)?o:null,ft[o]=i),r}});var pt=/^(?:input|select|textarea|button)$/i,dt=/^(?:a|area)$/i;function ht(e){return(e.match(P)||[]).join(" ")}function gt(e){return e.getAttribute&&e.getAttribute("class")||""}function vt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(P)||[]}S.fn.extend({prop:function(e,t){return $(this,S.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[S.propFix[e]||e]})}}),S.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&S.isXMLDoc(e)||(t=S.propFix[t]||t,i=S.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=S.find.attr(e,"tabindex");return t?parseInt(t,10):pt.test(e.nodeName)||dt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),y.optSelected||(S.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),S.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){S.propFix[this.toLowerCase()]=this}),S.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).addClass(t.call(this,e,gt(this)))});if((e=vt(t)).length)while(n=this[u++])if(i=gt(n),r=1===n.nodeType&&" "+ht(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=ht(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).removeClass(t.call(this,e,gt(this)))});if(!arguments.length)return this.attr("class","");if((e=vt(t)).length)while(n=this[u++])if(i=gt(n),r=1===n.nodeType&&" "+ht(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=ht(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){S(this).toggleClass(i.call(this,e,gt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=S(this),r=vt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=gt(this))&&Y.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Y.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+ht(gt(n))+" ").indexOf(t))return!0;return!1}});var yt=/\r/g;S.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,S(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=S.map(t,function(e){return null==e?"":e+""})),(r=S.valHooks[this.type]||S.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=S.valHooks[t.type]||S.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(yt,""):null==e?"":e:void 0}}),S.extend({valHooks:{option:{get:function(e){var t=S.find.attr(e,"value");return null!=t?t:ht(S.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,"optgroup"))){if(t=S(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=S.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<S.inArray(S.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),S.each(["radio","checkbox"],function(){S.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<S.inArray(S(e).val(),t)}},y.checkOn||(S.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in C;var mt=/^(?:focusinfocus|focusoutblur)$/,xt=function(e){e.stopPropagation()};S.extend(S.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,"type")?e.type:e,h=v.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!mt.test(d+S.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[S.expando]?e:new S.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:S.makeArray(t,[e]),c=S.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,mt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Y.get(o,"events")||Object.create(null))[e.type]&&Y.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&V(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!V(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),S.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,xt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,xt),S.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=S.extend(new S.Event,n,{type:e,isSimulated:!0});S.event.trigger(r,null,t)}}),S.fn.extend({trigger:function(e,t){return this.each(function(){S.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return S.event.trigger(e,t,n,!0)}}),y.focusin||S.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){S.event.simulate(r,e.target,S.event.fix(e))};S.event.special[r]={setup:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r);t||e.addEventListener(n,i,!0),Y.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r)-1;t?Y.access(e,r,t):(e.removeEventListener(n,i,!0),Y.remove(e,r))}}});var bt=C.location,wt={guid:Date.now()},Tt=/\?/;S.parseXML=function(e){var t,n;if(!e||"string"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,"text/xml")}catch(e){}return n=t&&t.getElementsByTagName("parsererror")[0],t&&!n||S.error("Invalid XML: "+(n?S.map(n.childNodes,function(e){return e.textContent}).join("\n"):e)),t};var Ct=/\[\]$/,Et=/\r?\n/g,St=/^(?:submit|button|image|reset|file)$/i,kt=/^(?:input|select|textarea|keygen)/i;function At(n,e,r,i){var t;if(Array.isArray(e))S.each(e,function(e,t){r||Ct.test(n)?i(n,t):At(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==w(e))i(n,e);else for(t in e)At(n+"["+t+"]",e[t],r,i)}S.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!S.isPlainObject(e))S.each(e,function(){i(this.name,this.value)});else for(n in e)At(n,e[n],t,i);return r.join("&")},S.fn.extend({serialize:function(){return S.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=S.prop(this,"elements");return e?S.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!S(this).is(":disabled")&&kt.test(this.nodeName)&&!St.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=S(this).val();return null==n?null:Array.isArray(n)?S.map(n,function(e){return{name:t.name,value:e.replace(Et,"\r\n")}}):{name:t.name,value:n.replace(Et,"\r\n")}}).get()}});var Nt=/%20/g,jt=/#.*$/,Dt=/([?&])_=[^&]*/,qt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Lt=/^(?:GET|HEAD)$/,Ht=/^\/\//,Ot={},Pt={},Rt="*/".concat("*"),Mt=E.createElement("a");function It(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(P)||[];if(m(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Wt(t,i,o,a){var s={},u=t===Pt;function l(e){var r;return s[e]=!0,S.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function Ft(e,t){var n,r,i=S.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&S.extend(!0,e,r),e}Mt.href=bt.href,S.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:bt.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(bt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Rt,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":S.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Ft(Ft(e,S.ajaxSettings),t):Ft(S.ajaxSettings,e)},ajaxPrefilter:It(Ot),ajaxTransport:It(Pt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=S.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?S(y):S.event,x=S.Deferred(),b=S.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=qt.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||bt.href)+"").replace(Ht,bt.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(P)||[""],null==v.crossDomain){r=E.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Mt.protocol+"//"+Mt.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=S.param(v.data,v.traditional)),Wt(Ot,v,t,T),h)return T;for(i in(g=S.event&&v.global)&&0==S.active++&&S.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Lt.test(v.type),f=v.url.replace(jt,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(Nt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(Tt.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Dt,"$1"),o=(Tt.test(f)?"&":"?")+"_="+wt.guid+++o),v.url=f+o),v.ifModified&&(S.lastModified[f]&&T.setRequestHeader("If-Modified-Since",S.lastModified[f]),S.etag[f]&&T.setRequestHeader("If-None-Match",S.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+Rt+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Wt(Pt,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),!i&&-1<S.inArray("script",v.dataTypes)&&S.inArray("json",v.dataTypes)<0&&(v.converters["text script"]=function(){}),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(S.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(S.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--S.active||S.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return S.get(e,t,n,"json")},getScript:function(e,t){return S.get(e,void 0,t,"script")}}),S.each(["get","post"],function(e,i){S[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),S.ajax(S.extend({url:e,type:i,dataType:r,data:t,success:n},S.isPlainObject(e)&&e))}}),S.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),S._evalUrl=function(e,t,n){return S.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){S.globalEval(e,t,n)}})},S.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=S(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){S(this).wrapInner(n.call(this,e))}):this.each(function(){var e=S(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){S(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){S(this).replaceWith(this.childNodes)}),this}}),S.expr.pseudos.hidden=function(e){return!S.expr.pseudos.visible(e)},S.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},S.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var Bt={0:200,1223:204},$t=S.ajaxSettings.xhr();y.cors=!!$t&&"withCredentials"in $t,y.ajax=$t=!!$t,S.ajaxTransport(function(i){var o,a;if(y.cors||$t&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(Bt[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),S.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),S.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return S.globalEval(e),e}}}),S.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),S.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=S("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=ht(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&S.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?S("<div>").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var Xt=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;S.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||S.guid++,i},S.holdReady=function(e){e?S.readyWait++:S.ready(!0)},S.isArray=Array.isArray,S.parseJSON=JSON.parse,S.nodeName=A,S.isFunction=m,S.isWindow=x,S.camelCase=X,S.type=w,S.now=Date.now,S.isNumeric=function(e){var t=S.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},S.trim=function(e){return null==e?"":(e+"").replace(Xt,"")},"function"==typeof define&&define.amd&&define("jquery",[],function(){return S});var Vt=C.jQuery,Gt=C.$;return S.noConflict=function(e){return C.$===S&&(C.$=Gt),e&&C.jQuery===S&&(C.jQuery=Vt),S},"undefined"==typeof e&&(C.jQuery=C.$=S),S});
-
-
-
@@ -0,0 +1,1 @@!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}});
-
-
-
@@ -0,0 +1,4 @@/** * @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed */ !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document);
-
-
-
@@ -0,0 +1,4 @@/** * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed */ !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document);
-
-
html/_static/js/theme.js (new)
-
@@ -0,0 +1,1 @@!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("<div class='wy-table-responsive'></div>"),n("table.docutils.footnote").wrap("<div class='wy-table-responsive footnote'></div>"),n("table.docutils.citation").wrap("<div class='wy-table-responsive citation'></div>"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n('<button class="toctree-expand" title="Open/close menu"></button>'),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t<e.length&&!window.requestAnimationFrame;++t)window.requestAnimationFrame=window[e[t]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[e[t]+"CancelAnimationFrame"]||window[e[t]+"CancelRequestAnimationFrame"];window.requestAnimationFrame||(window.requestAnimationFrame=function(e,t){var i=(new Date).getTime(),o=Math.max(0,16-(i-n)),r=window.setTimeout((function(){e(i+o)}),o);return n=i+o,r}),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(n){clearTimeout(n)})}()}).call(window)},function(n,e){n.exports=jQuery},function(n,e,t){}]);
-
-
-
@@ -0,0 +1,199 @@/* * language_data.js * ~~~~~~~~~~~~~~~~ * * This script contains the language-specific data used by searchtools.js, * namely the list of stopwords, stemmer, scorer and splitter. * * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; /* Non-minified version is copied as a separate JS file, is available */ /** * Porter Stemmer */ var Stemmer = function() { var step2list = { ational: 'ate', tional: 'tion', enci: 'ence', anci: 'ance', izer: 'ize', bli: 'ble', alli: 'al', entli: 'ent', eli: 'e', ousli: 'ous', ization: 'ize', ation: 'ate', ator: 'ate', alism: 'al', iveness: 'ive', fulness: 'ful', ousness: 'ous', aliti: 'al', iviti: 'ive', biliti: 'ble', logi: 'log' }; var step3list = { icate: 'ic', ative: '', alize: 'al', iciti: 'ic', ical: 'ic', ful: '', ness: '' }; var c = "[^aeiou]"; // consonant var v = "[aeiouy]"; // vowel var C = c + "[^aeiouy]*"; // consonant sequence var V = v + "[aeiou]*"; // vowel sequence var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 var s_v = "^(" + C + ")?" + v; // vowel in stem this.stemWord = function (w) { var stem; var suffix; var firstch; var origword = w; if (w.length < 3) return w; var re; var re2; var re3; var re4; firstch = w.substr(0,1); if (firstch == "y") w = firstch.toUpperCase() + w.substr(1); // Step 1a re = /^(.+?)(ss|i)es$/; re2 = /^(.+?)([^s])s$/; if (re.test(w)) w = w.replace(re,"$1$2"); else if (re2.test(w)) w = w.replace(re2,"$1$2"); // Step 1b re = /^(.+?)eed$/; re2 = /^(.+?)(ed|ing)$/; if (re.test(w)) { var fp = re.exec(w); re = new RegExp(mgr0); if (re.test(fp[1])) { re = /.$/; w = w.replace(re,""); } } else if (re2.test(w)) { var fp = re2.exec(w); stem = fp[1]; re2 = new RegExp(s_v); if (re2.test(stem)) { w = stem; re2 = /(at|bl|iz)$/; re3 = new RegExp("([^aeiouylsz])\\1$"); re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); if (re2.test(w)) w = w + "e"; else if (re3.test(w)) { re = /.$/; w = w.replace(re,""); } else if (re4.test(w)) w = w + "e"; } } // Step 1c re = /^(.+?)y$/; if (re.test(w)) { var fp = re.exec(w); stem = fp[1]; re = new RegExp(s_v); if (re.test(stem)) w = stem + "i"; } // Step 2 re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; if (re.test(w)) { var fp = re.exec(w); stem = fp[1]; suffix = fp[2]; re = new RegExp(mgr0); if (re.test(stem)) w = stem + step2list[suffix]; } // Step 3 re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; if (re.test(w)) { var fp = re.exec(w); stem = fp[1]; suffix = fp[2]; re = new RegExp(mgr0); if (re.test(stem)) w = stem + step3list[suffix]; } // Step 4 re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; re2 = /^(.+?)(s|t)(ion)$/; if (re.test(w)) { var fp = re.exec(w); stem = fp[1]; re = new RegExp(mgr1); if (re.test(stem)) w = stem; } else if (re2.test(w)) { var fp = re2.exec(w); stem = fp[1] + fp[2]; re2 = new RegExp(mgr1); if (re2.test(stem)) w = stem; } // Step 5 re = /^(.+?)e$/; if (re.test(w)) { var fp = re.exec(w); stem = fp[1]; re = new RegExp(mgr1); re2 = new RegExp(meq1); re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) w = stem; } re = /ll$/; re2 = new RegExp(mgr1); if (re.test(w) && re2.test(w)) { re = /.$/; w = w.replace(re,""); } // and turn initial Y back to y if (firstch == "y") w = firstch.toLowerCase() + w.substr(1); return w; } }
-
-
html/_static/minus.png (new)
-
html/_static/plus.png (new)
-
-
@@ -0,0 +1,74 @@pre { line-height: 125%; } td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } .highlight .hll { background-color: #ffffcc } .highlight { background: #f8f8f8; } .highlight .c { color: #3D7B7B; font-style: italic } /* Comment */ .highlight .err { border: 1px solid #FF0000 } /* Error */ .highlight .k { color: #008000; font-weight: bold } /* Keyword */ .highlight .o { color: #666666 } /* Operator */ .highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ .highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ .highlight .cp { color: #9C6500 } /* Comment.Preproc */ .highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ .highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ .highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ .highlight .gd { color: #A00000 } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #E40000 } /* Generic.Error */ .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ .highlight .gi { color: #008400 } /* Generic.Inserted */ .highlight .go { color: #717171 } /* Generic.Output */ .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ .highlight .gt { color: #0044DD } /* Generic.Traceback */ .highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008000 } /* Keyword.Pseudo */ .highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #B00040 } /* Keyword.Type */ .highlight .m { color: #666666 } /* Literal.Number */ .highlight .s { color: #BA2121 } /* Literal.String */ .highlight .na { color: #687822 } /* Name.Attribute */ .highlight .nb { color: #008000 } /* Name.Builtin */ .highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ .highlight .no { color: #880000 } /* Name.Constant */ .highlight .nd { color: #AA22FF } /* Name.Decorator */ .highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */ .highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0000FF } /* Name.Function */ .highlight .nl { color: #767600 } /* Name.Label */ .highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #19177C } /* Name.Variable */ .highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #666666 } /* Literal.Number.Bin */ .highlight .mf { color: #666666 } /* Literal.Number.Float */ .highlight .mh { color: #666666 } /* Literal.Number.Hex */ .highlight .mi { color: #666666 } /* Literal.Number.Integer */ .highlight .mo { color: #666666 } /* Literal.Number.Oct */ .highlight .sa { color: #BA2121 } /* Literal.String.Affix */ .highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ .highlight .sc { color: #BA2121 } /* Literal.String.Char */ .highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */ .highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ .highlight .s2 { color: #BA2121 } /* Literal.String.Double */ .highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ .highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ .highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ .highlight .sx { color: #008000 } /* Literal.String.Other */ .highlight .sr { color: #A45A77 } /* Literal.String.Regex */ .highlight .s1 { color: #BA2121 } /* Literal.String.Single */ .highlight .ss { color: #19177C } /* Literal.String.Symbol */ .highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0000FF } /* Name.Function.Magic */ .highlight .vc { color: #19177C } /* Name.Variable.Class */ .highlight .vg { color: #19177C } /* Name.Variable.Global */ .highlight .vi { color: #19177C } /* Name.Variable.Instance */ .highlight .vm { color: #19177C } /* Name.Variable.Magic */ .highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
-
-
-
@@ -0,0 +1,566 @@/* * searchtools.js * ~~~~~~~~~~~~~~~~ * * Sphinx JavaScript utilities for the full-text search. * * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ "use strict"; /** * Simple result scoring code. */ if (typeof Scorer === "undefined") { var Scorer = { // Implement the following function to further tweak the score for each result // The function takes a result array [docname, title, anchor, descr, score, filename] // and returns the new score. /* score: result => { const [docname, title, anchor, descr, score, filename] = result return score }, */ // query matches the full name of an object objNameMatch: 11, // or matches in the last dotted part of the object name objPartialMatch: 6, // Additive scores depending on the priority of the object objPrio: { 0: 15, // used to be importantResults 1: 5, // used to be objectResults 2: -5, // used to be unimportantResults }, // Used when the priority is not in the mapping. objPrioDefault: 0, // query found in title title: 15, partialTitle: 7, // query found in terms term: 5, partialTerm: 2, }; } const _removeChildren = (element) => { while (element && element.lastChild) element.removeChild(element.lastChild); }; /** * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping */ const _escapeRegExp = (string) => string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string const _displayItem = (item, searchTerms) => { const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; const docUrlRoot = DOCUMENTATION_OPTIONS.URL_ROOT; const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; const [docName, title, anchor, descr, score, _filename] = item; let listItem = document.createElement("li"); let requestUrl; let linkUrl; if (docBuilder === "dirhtml") { // dirhtml builder let dirname = docName + "/"; if (dirname.match(/\/index\/$/)) dirname = dirname.substring(0, dirname.length - 6); else if (dirname === "index/") dirname = ""; requestUrl = docUrlRoot + dirname; linkUrl = requestUrl; } else { // normal html builders requestUrl = docUrlRoot + docName + docFileSuffix; linkUrl = docName + docLinkSuffix; } let linkEl = listItem.appendChild(document.createElement("a")); linkEl.href = linkUrl + anchor; linkEl.dataset.score = score; linkEl.innerHTML = title; if (descr) listItem.appendChild(document.createElement("span")).innerHTML = " (" + descr + ")"; else if (showSearchSummary) fetch(requestUrl) .then((responseData) => responseData.text()) .then((data) => { if (data) listItem.appendChild( Search.makeSearchSummary(data, searchTerms) ); }); Search.output.appendChild(listItem); }; const _finishSearch = (resultCount) => { Search.stopPulse(); Search.title.innerText = _("Search Results"); if (!resultCount) Search.status.innerText = Documentation.gettext( "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." ); else Search.status.innerText = _( `Search finished, found ${resultCount} page(s) matching the search query.` ); }; const _displayNextItem = ( results, resultCount, searchTerms ) => { // results left, load the summary and display it // this is intended to be dynamic (don't sub resultsCount) if (results.length) { _displayItem(results.pop(), searchTerms); setTimeout( () => _displayNextItem(results, resultCount, searchTerms), 5 ); } // search finished, update title and status message else _finishSearch(resultCount); }; /** * Default splitQuery function. Can be overridden in ``sphinx.search`` with a * custom function per language. * * The regular expression works by splitting the string on consecutive characters * that are not Unicode letters, numbers, underscores, or emoji characters. * This is the same as ``\W+`` in Python, preserving the surrogate pair area. */ if (typeof splitQuery === "undefined") { var splitQuery = (query) => query .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) .filter(term => term) // remove remaining empty strings } /** * Search Module */ const Search = { _index: null, _queued_query: null, _pulse_status: -1, htmlToText: (htmlString) => { const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); const docContent = htmlElement.querySelector('[role="main"]'); if (docContent !== undefined) return docContent.textContent; console.warn( "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." ); return ""; }, init: () => { const query = new URLSearchParams(window.location.search).get("q"); document .querySelectorAll('input[name="q"]') .forEach((el) => (el.value = query)); if (query) Search.performSearch(query); }, loadIndex: (url) => (document.body.appendChild(document.createElement("script")).src = url), setIndex: (index) => { Search._index = index; if (Search._queued_query !== null) { const query = Search._queued_query; Search._queued_query = null; Search.query(query); } }, hasIndex: () => Search._index !== null, deferQuery: (query) => (Search._queued_query = query), stopPulse: () => (Search._pulse_status = -1), startPulse: () => { if (Search._pulse_status >= 0) return; const pulse = () => { Search._pulse_status = (Search._pulse_status + 1) % 4; Search.dots.innerText = ".".repeat(Search._pulse_status); if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); }; pulse(); }, /** * perform a search for something (or wait until index is loaded) */ performSearch: (query) => { // create the required interface elements const searchText = document.createElement("h2"); searchText.textContent = _("Searching"); const searchSummary = document.createElement("p"); searchSummary.classList.add("search-summary"); searchSummary.innerText = ""; const searchList = document.createElement("ul"); searchList.classList.add("search"); const out = document.getElementById("search-results"); Search.title = out.appendChild(searchText); Search.dots = Search.title.appendChild(document.createElement("span")); Search.status = out.appendChild(searchSummary); Search.output = out.appendChild(searchList); const searchProgress = document.getElementById("search-progress"); // Some themes don't use the search progress node if (searchProgress) { searchProgress.innerText = _("Preparing search..."); } Search.startPulse(); // index already loaded, the browser was quick! if (Search.hasIndex()) Search.query(query); else Search.deferQuery(query); }, /** * execute search (requires search index to be loaded) */ query: (query) => { const filenames = Search._index.filenames; const docNames = Search._index.docnames; const titles = Search._index.titles; const allTitles = Search._index.alltitles; const indexEntries = Search._index.indexentries; // stem the search terms and add them to the correct list const stemmer = new Stemmer(); const searchTerms = new Set(); const excludedTerms = new Set(); const highlightTerms = new Set(); const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); splitQuery(query.trim()).forEach((queryTerm) => { const queryTermLower = queryTerm.toLowerCase(); // maybe skip this "word" // stopwords array is from language_data.js if ( stopwords.indexOf(queryTermLower) !== -1 || queryTerm.match(/^\d+$/) ) return; // stem the word let word = stemmer.stemWord(queryTermLower); // select the correct list if (word[0] === "-") excludedTerms.add(word.substr(1)); else { searchTerms.add(word); highlightTerms.add(queryTermLower); } }); if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) } // console.debug("SEARCH: searching for:"); // console.info("required: ", [...searchTerms]); // console.info("excluded: ", [...excludedTerms]); // array of [docname, title, anchor, descr, score, filename] let results = []; _removeChildren(document.getElementById("search-progress")); const queryLower = query.toLowerCase(); for (const [title, foundTitles] of Object.entries(allTitles)) { if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { for (const [file, id] of foundTitles) { let score = Math.round(100 * queryLower.length / title.length) results.push([ docNames[file], titles[file] !== title ? `${titles[file]} > ${title}` : title, id !== null ? "#" + id : "", null, score, filenames[file], ]); } } } // search for explicit entries in index directives for (const [entry, foundEntries] of Object.entries(indexEntries)) { if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { for (const [file, id] of foundEntries) { let score = Math.round(100 * queryLower.length / entry.length) results.push([ docNames[file], titles[file], id ? "#" + id : "", null, score, filenames[file], ]); } } } // lookup as object objectTerms.forEach((term) => results.push(...Search.performObjectSearch(term, objectTerms)) ); // lookup as search terms in fulltext results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); // let the scorer override scores with a custom scoring function if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); // now sort the results by score (in opposite order of appearance, since the // display function below uses pop() to retrieve items) and then // alphabetically results.sort((a, b) => { const leftScore = a[4]; const rightScore = b[4]; if (leftScore === rightScore) { // same score: sort alphabetically const leftTitle = a[1].toLowerCase(); const rightTitle = b[1].toLowerCase(); if (leftTitle === rightTitle) return 0; return leftTitle > rightTitle ? -1 : 1; // inverted is intentional } return leftScore > rightScore ? 1 : -1; }); // remove duplicate search results // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept let seen = new Set(); results = results.reverse().reduce((acc, result) => { let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); if (!seen.has(resultStr)) { acc.push(result); seen.add(resultStr); } return acc; }, []); results = results.reverse(); // for debugging //Search.lastresults = results.slice(); // a copy // console.info("search results:", Search.lastresults); // print the results _displayNextItem(results, results.length, searchTerms); }, /** * search for object names */ performObjectSearch: (object, objectTerms) => { const filenames = Search._index.filenames; const docNames = Search._index.docnames; const objects = Search._index.objects; const objNames = Search._index.objnames; const titles = Search._index.titles; const results = []; const objectSearchCallback = (prefix, match) => { const name = match[4] const fullname = (prefix ? prefix + "." : "") + name; const fullnameLower = fullname.toLowerCase(); if (fullnameLower.indexOf(object) < 0) return; let score = 0; const parts = fullnameLower.split("."); // check for different match types: exact matches of full name or // "last name" (i.e. last dotted part) if (fullnameLower === object || parts.slice(-1)[0] === object) score += Scorer.objNameMatch; else if (parts.slice(-1)[0].indexOf(object) > -1) score += Scorer.objPartialMatch; // matches in last name const objName = objNames[match[1]][2]; const title = titles[match[0]]; // If more than one term searched for, we require other words to be // found in the name/title/description const otherTerms = new Set(objectTerms); otherTerms.delete(object); if (otherTerms.size > 0) { const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); if ( [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) ) return; } let anchor = match[3]; if (anchor === "") anchor = fullname; else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; const descr = objName + _(", in ") + title; // add custom score for some objects according to scorer if (Scorer.objPrio.hasOwnProperty(match[2])) score += Scorer.objPrio[match[2]]; else score += Scorer.objPrioDefault; results.push([ docNames[match[0]], fullname, "#" + anchor, descr, score, filenames[match[0]], ]); }; Object.keys(objects).forEach((prefix) => objects[prefix].forEach((array) => objectSearchCallback(prefix, array) ) ); return results; }, /** * search for full-text terms in the index */ performTermsSearch: (searchTerms, excludedTerms) => { // prepare search const terms = Search._index.terms; const titleTerms = Search._index.titleterms; const filenames = Search._index.filenames; const docNames = Search._index.docnames; const titles = Search._index.titles; const scoreMap = new Map(); const fileMap = new Map(); // perform the search on the required terms searchTerms.forEach((word) => { const files = []; const arr = [ { files: terms[word], score: Scorer.term }, { files: titleTerms[word], score: Scorer.title }, ]; // add support for partial matches if (word.length > 2) { const escapedWord = _escapeRegExp(word); Object.keys(terms).forEach((term) => { if (term.match(escapedWord) && !terms[word]) arr.push({ files: terms[term], score: Scorer.partialTerm }); }); Object.keys(titleTerms).forEach((term) => { if (term.match(escapedWord) && !titleTerms[word]) arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); }); } // no match but word was a required one if (arr.every((record) => record.files === undefined)) return; // found search word in contents arr.forEach((record) => { if (record.files === undefined) return; let recordFiles = record.files; if (recordFiles.length === undefined) recordFiles = [recordFiles]; files.push(...recordFiles); // set score for the word in each file recordFiles.forEach((file) => { if (!scoreMap.has(file)) scoreMap.set(file, {}); scoreMap.get(file)[word] = record.score; }); }); // create the mapping files.forEach((file) => { if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word); else fileMap.set(file, [word]); }); }); // now check if the files don't contain excluded terms const results = []; for (const [file, wordList] of fileMap) { // check if all requirements are matched // as search terms with length < 3 are discarded const filteredTermCount = [...searchTerms].filter( (term) => term.length > 2 ).length; if ( wordList.length !== searchTerms.size && wordList.length !== filteredTermCount ) continue; // ensure that none of the excluded terms is in the search result if ( [...excludedTerms].some( (term) => terms[term] === file || titleTerms[term] === file || (terms[term] || []).includes(file) || (titleTerms[term] || []).includes(file) ) ) break; // select one (max) score for the file. const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); // add result to the result list results.push([ docNames[file], titles[file], "", null, score, filenames[file], ]); } return results; }, /** * helper function to return a node containing the * search summary for a given text. keywords is a list * of stemmed words. */ makeSearchSummary: (htmlText, keywords) => { const text = Search.htmlToText(htmlText); if (text === "") return null; const textLower = text.toLowerCase(); const actualStartPosition = [...keywords] .map((k) => textLower.indexOf(k.toLowerCase())) .filter((i) => i > -1) .slice(-1)[0]; const startWithContext = Math.max(actualStartPosition - 120, 0); const top = startWithContext === 0 ? "" : "..."; const tail = startWithContext + 240 < text.length ? "..." : ""; let summary = document.createElement("p"); summary.classList.add("context"); summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; return summary; }, }; _ready(Search.init);
-
-
-
@@ -0,0 +1,144 @@/* Highlighting utilities for Sphinx HTML documentation. */ "use strict"; const SPHINX_HIGHLIGHT_ENABLED = true /** * highlight a given string on a node by wrapping it in * span elements with the given class name. */ const _highlight = (node, addItems, text, className) => { if (node.nodeType === Node.TEXT_NODE) { const val = node.nodeValue; const parent = node.parentNode; const pos = val.toLowerCase().indexOf(text); if ( pos >= 0 && !parent.classList.contains(className) && !parent.classList.contains("nohighlight") ) { let span; const closestNode = parent.closest("body, svg, foreignObject"); const isInSVG = closestNode && closestNode.matches("svg"); if (isInSVG) { span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); } else { span = document.createElement("span"); span.classList.add(className); } span.appendChild(document.createTextNode(val.substr(pos, text.length))); parent.insertBefore( span, parent.insertBefore( document.createTextNode(val.substr(pos + text.length)), node.nextSibling ) ); node.nodeValue = val.substr(0, pos); if (isInSVG) { const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" ); const bbox = parent.getBBox(); rect.x.baseVal.value = bbox.x; rect.y.baseVal.value = bbox.y; rect.width.baseVal.value = bbox.width; rect.height.baseVal.value = bbox.height; rect.setAttribute("class", className); addItems.push({ parent: parent, target: rect }); } } } else if (node.matches && !node.matches("button, select, textarea")) { node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); } }; const _highlightText = (thisNode, text, className) => { let addItems = []; _highlight(thisNode, addItems, text, className); addItems.forEach((obj) => obj.parent.insertAdjacentElement("beforebegin", obj.target) ); }; /** * Small JavaScript module for the documentation. */ const SphinxHighlight = { /** * highlight the search words provided in localstorage in the text */ highlightSearchWords: () => { if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight // get and clear terms from localstorage const url = new URL(window.location); const highlight = localStorage.getItem("sphinx_highlight_terms") || url.searchParams.get("highlight") || ""; localStorage.removeItem("sphinx_highlight_terms") url.searchParams.delete("highlight"); window.history.replaceState({}, "", url); // get individual terms from highlight string const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); if (terms.length === 0) return; // nothing to do // There should never be more than one element matching "div.body" const divBody = document.querySelectorAll("div.body"); const body = divBody.length ? divBody[0] : document.querySelector("body"); window.setTimeout(() => { terms.forEach((term) => _highlightText(body, term, "highlighted")); }, 10); const searchBox = document.getElementById("searchbox"); if (searchBox === null) return; searchBox.appendChild( document .createRange() .createContextualFragment( '<p class="highlight-link">' + '<a href="javascript:SphinxHighlight.hideSearchWords()">' + _("Hide Search Matches") + "</a></p>" ) ); }, /** * helper function to hide the search marks again */ hideSearchWords: () => { document .querySelectorAll("#searchbox .highlight-link") .forEach((el) => el.remove()); document .querySelectorAll("span.highlighted") .forEach((el) => el.classList.remove("highlighted")); localStorage.removeItem("sphinx_highlight_terms") }, initEscapeListener: () => { // only install a listener if it is really needed if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; document.addEventListener("keydown", (event) => { // bail for input elements if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; // bail with special keys if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { SphinxHighlight.hideSearchWords(); event.preventDefault(); } }); }, }; _ready(SphinxHighlight.highlightSearchWords); _ready(SphinxHighlight.initEscapeListener);
-
-
html/genindex.html (new)
-
@@ -0,0 +1,553 @@<!DOCTYPE html> <html class="writer-html5" lang="en" > <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Index — Mathematics in Lean 0.1 documentation</title> <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> <link rel="stylesheet" href="_static/css/custom.css" type="text/css" /> <link rel="shortcut icon" href="_static/favicon.ico"/> <!--[if lt IE 9]> <script src="_static/js/html5shiv.min.js"></script> <![endif]--> <script src="_static/jquery.js"></script> <script src="_static/_sphinx_javascript_frameworks_compat.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script src="_static/doctools.js"></script> <script src="_static/sphinx_highlight.js"></script> <script src="_static/js/theme.js"></script> <link rel="index" title="Index" href="#" /> <link rel="search" title="Search" href="search.html" /> </head> <body class="wy-body-for-nav"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search" > <a href="index.html" class="icon icon-home"> Mathematics in Lean </a> <div role="search"> <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> <ul> <li class="toctree-l1"><a class="reference internal" href="C01_Introduction.html">1. Introduction</a></li> <li class="toctree-l1"><a class="reference internal" href="C02_Basics.html">2. Basics</a></li> <li class="toctree-l1"><a class="reference internal" href="C03_Logic.html">3. Logic</a></li> <li class="toctree-l1"><a class="reference internal" href="C04_Sets_and_Functions.html">4. Sets and Functions</a></li> <li class="toctree-l1"><a class="reference internal" href="C05_Number_Theory.html">5. Number Theory</a></li> <li class="toctree-l1"><a class="reference internal" href="C06_Structures.html">6. Structures</a></li> <li class="toctree-l1"><a class="reference internal" href="C07_Hierarchies.html">7. Hierarchies</a></li> <li class="toctree-l1"><a class="reference internal" href="C08_Topology.html">8. Topology</a></li> <li class="toctree-l1"><a class="reference internal" href="C09_Differential_Calculus.html">9. Differential Calculus</a></li> </ul> <ul class="current"> <li class="toctree-l1 current"><a class="current reference internal" href="#">Index</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="index.html">Mathematics in Lean</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="Page navigation"> <ul class="wy-breadcrumbs"> <li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li> <li class="breadcrumb-item active">Index</li> <li class="wy-breadcrumbs-aside"> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <h1 id="index">Index</h1> <div class="genindex-jumpbox"> <a href="#A"><strong>A</strong></a> | <a href="#B"><strong>B</strong></a> | <a href="#C"><strong>C</strong></a> | <a href="#D"><strong>D</strong></a> | <a href="#E"><strong>E</strong></a> | <a href="#F"><strong>F</strong></a> | <a href="#G"><strong>G</strong></a> | <a href="#H"><strong>H</strong></a> | <a href="#I"><strong>I</strong></a> | <a href="#L"><strong>L</strong></a> | <a href="#M"><strong>M</strong></a> | <a href="#N"><strong>N</strong></a> | <a href="#O"><strong>O</strong></a> | <a href="#P"><strong>P</strong></a> | <a href="#R"><strong>R</strong></a> | <a href="#S"><strong>S</strong></a> | <a href="#T"><strong>T</strong></a> | <a href="#U"><strong>U</strong></a> </div> <h2 id="A">A</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-23">absolute value</a> </li> <li><a href="C03_Logic.html#index-17">absurd</a> </li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C03_Logic.html#index-7">anonymous constructor</a> </li> <li><a href="C02_Basics.html#index-16">apply</a> </li> <li><a href="C03_Logic.html#index-19">assumption</a> </li> </ul></td> </tr></table> <h2 id="B">B</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C04_Sets_and_Functions.html#index-3">bounded quantifiers</a> </li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C03_Logic.html#index-23">by_cases</a> </li> <li><a href="C03_Logic.html#index-14">by_contra</a> </li> </ul></td> </tr></table> <h2 id="C">C</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-3">calc</a> </li> <li><a href="C03_Logic.html#index-8">cases</a> </li> <li><a href="C03_Logic.html#index-2">change</a> </li> <li><a href="C01_Introduction.html#index-0">check</a> </li> <li> command <ul> <li><a href="C02_Basics.html#index-9">open</a> </li> </ul></li> <li> commands <ul> <li><a href="C01_Introduction.html#index-0">check</a> </li> </ul></li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-8">commutative ring</a> </li> <li><a href="C03_Logic.html#index-25">congr</a> </li> <li><a href="C03_Logic.html#index-18">constructor</a> </li> <li><a href="C08_Topology.html#index-3">continuity</a> </li> <li><a href="C03_Logic.html#index-17">contradiction</a> </li> <li><a href="C03_Logic.html#index-16">contrapose</a> </li> <li><a href="C03_Logic.html#index-26">convert</a> </li> </ul></td> </tr></table> <h2 id="D">D</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-12">definitional equality</a> </li> <li><a href="C09_Differential_Calculus.html#index-0">differential calculus</a> </li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-24">divisibility</a> </li> <li><a href="C03_Logic.html#index-2">dsimp</a> </li> </ul></td> </tr></table> <h2 id="E">E</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C09_Differential_Calculus.html#index-1">elementary calculus</a> </li> <li><a href="C03_Logic.html#index-4">erw</a> </li> <li><a href="C02_Basics.html#index-5">exact</a> </li> <li><a href="C03_Logic.html#index-22">excluded middle</a> </li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C03_Logic.html#index-17">exfalso</a> </li> <li><a href="C02_Basics.html#index-18">exponential</a> </li> <li><a href="C03_Logic.html#index-24">ext</a> </li> <li><a href="C03_Logic.html#index-24">extensionality</a> </li> </ul></td> </tr></table> <h2 id="F">F</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C03_Logic.html#index-11">field_simp</a> </li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C08_Topology.html#index-1">Filter</a> </li> <li><a href="C03_Logic.html#index-12">from</a> </li> </ul></td> </tr></table> <h2 id="G">G</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-25">gcd</a> </li> <li><a href="C02_Basics.html#index-2">goal</a> </li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-13">group (algebraic structure)</a> <ul> <li><a href="C02_Basics.html#index-14">(tactic)</a> </li> </ul></li> </ul></td> </tr></table> <h2 id="H">H</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-11">have</a>, <a href="C03_Logic.html#index-12">[1]</a> </li> </ul></td> </tr></table> <h2 id="I">I</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-10">implicit argument</a> </li> <li><a href="C02_Basics.html#index-15">inequalities</a> </li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C03_Logic.html#index-5">injective function</a> </li> <li><a href="C10_Integration_and_Measure_Theory.html#index-0">integration</a> </li> <li><a href="C03_Logic.html#index-0">intro</a> </li> </ul></td> </tr></table> <h2 id="L">L</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C03_Logic.html#index-1">lambda abstraction</a> </li> <li><a href="C02_Basics.html#index-27">lattice</a> </li> <li><a href="C02_Basics.html#index-25">lcm</a> </li> <li><a href="C03_Logic.html#index-21">left</a> </li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C03_Logic.html#index-13">let</a> </li> <li><a href="C02_Basics.html#index-17">linarith</a> </li> <li><a href="C02_Basics.html#index-2">local context</a> </li> <li><a href="C02_Basics.html#index-18">logarithm</a> </li> </ul></td> </tr></table> <h2 id="M">M</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-20">max</a> </li> <li><a href="C02_Basics.html#index-28">metric space</a>, <a href="C08_Topology.html#index-2">[1]</a> </li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-20">min</a> </li> <li><a href="C03_Logic.html#index-3">monotone function</a> </li> </ul></td> </tr></table> <h2 id="N">N</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-9">namespace</a> </li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-19">norm_num</a> </li> <li><a href="C09_Differential_Calculus.html#index-2">normed space</a> </li> </ul></td> </tr></table> <h2 id="O">O</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-9">open</a> </li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-26">order relation</a> </li> </ul></td> </tr></table> <h2 id="P">P</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-26">partial order</a> </li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C02_Basics.html#index-2">proof state</a> </li> <li><a href="C03_Logic.html#index-15">push_neg</a> </li> </ul></td> </tr></table> <h2 id="R">R</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C03_Logic.html#index-9">rcases</a> </li> <li><a href="C02_Basics.html#index-1">real numbers</a> </li> <li><a href="C02_Basics.html#index-12">reflexivity</a> </li> <li><a href="C02_Basics.html#index-22">repeat</a> </li> <li><a href="C02_Basics.html#index-0">rewrite</a> </li> <li><a href="C02_Basics.html#index-12">rfl</a> </li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C03_Logic.html#index-21">right</a> </li> <li><a href="C02_Basics.html#index-7">ring (algebraic structure)</a> <ul> <li><a href="C02_Basics.html#index-6">(tactic)</a> </li> </ul></li> <li><a href="C03_Logic.html#index-9">rintro</a> </li> <li><a href="C02_Basics.html#index-0">rw</a>, <a href="C02_Basics.html#index-4">[1]</a> </li> <li><a href="C04_Sets_and_Functions.html#index-2">rwa</a> </li> </ul></td> </tr></table> <h2 id="S">S</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C04_Sets_and_Functions.html#index-0">set operations</a> </li> <li><a href="C02_Basics.html#index-21">show</a> </li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C03_Logic.html#index-20">simp</a>, <a href="C04_Sets_and_Functions.html#index-1">[1]</a> </li> <li><a href="C03_Logic.html#index-10">surjective function</a> </li> </ul></td> </tr></table> <h2 id="T">T</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li> tactic <ul> <li><a href="C03_Logic.html#index-11">field_simp</a> </li> </ul></li> <li> tactics <ul> <li><a href="C02_Basics.html#index-14">abel</a> </li> <li><a href="C02_Basics.html#index-16">apply</a> </li> <li><a href="C03_Logic.html#index-19">assumption</a> </li> <li><a href="C03_Logic.html#index-23">by_cases</a> </li> <li><a href="C03_Logic.html#index-14">by_contra and by_contradiction</a> </li> <li><a href="C02_Basics.html#index-3">calc</a> </li> <li><a href="C03_Logic.html#index-8">cases</a> </li> <li><a href="C03_Logic.html#index-2">change</a> </li> <li><a href="C03_Logic.html#index-25">congr</a> </li> <li><a href="C03_Logic.html#index-18">constructor</a> </li> <li><a href="C08_Topology.html#index-3">continuity</a> </li> <li><a href="C03_Logic.html#index-17">contradiction</a> </li> <li><a href="C03_Logic.html#index-16">contrapose</a> </li> <li><a href="C03_Logic.html#index-26">convert</a> </li> <li><a href="C03_Logic.html#index-2">dsimp</a> </li> <li><a href="C03_Logic.html#index-4">erw</a> </li> <li><a href="C02_Basics.html#index-5">exact</a> </li> <li><a href="C03_Logic.html#index-17">exfalso</a> </li> <li><a href="C03_Logic.html#index-24">ext</a> </li> <li><a href="C03_Logic.html#index-12">from</a> </li> <li><a href="C02_Basics.html#index-14">group</a> </li> <li><a href="C02_Basics.html#index-11">have</a>, <a href="C03_Logic.html#index-12">[1]</a> </li> <li><a href="C03_Logic.html#index-0">intro</a> </li> <li><a href="C03_Logic.html#index-21">left</a> </li> <li><a href="C03_Logic.html#index-13">let</a> </li> <li><a href="C02_Basics.html#index-17">linarith</a> </li> <li><a href="C02_Basics.html#index-14">noncomm_ring</a> </li> <li><a href="C02_Basics.html#index-19">norm_num</a> </li> <li><a href="C03_Logic.html#index-15">push_neg</a> </li> <li><a href="C03_Logic.html#index-9">rcases</a> </li> <li><a href="C02_Basics.html#index-12">refl and reflexivity</a> </li> <li><a href="C02_Basics.html#index-22">repeat</a> </li> <li><a href="C03_Logic.html#index-21">right</a> </li> <li><a href="C02_Basics.html#index-6">ring</a> </li> <li><a href="C03_Logic.html#index-9">rintro</a> </li> <li><a href="C02_Basics.html#index-0">rw and rewrite</a>, <a href="C02_Basics.html#index-4">[1]</a> </li> <li><a href="C04_Sets_and_Functions.html#index-2">rwa</a> </li> <li><a href="C02_Basics.html#index-21">show</a> </li> <li><a href="C03_Logic.html#index-20">simp</a>, <a href="C04_Sets_and_Functions.html#index-1">[1]</a> </li> <li><a href="C03_Logic.html#index-6">use</a> </li> </ul></li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C03_Logic.html#index-12">this</a> </li> <li><a href="C08_Topology.html#index-4">topological space</a> </li> <li><a href="C08_Topology.html#index-0">topology</a> </li> </ul></td> </tr></table> <h2 id="U">U</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> <li><a href="C03_Logic.html#index-6">use</a> </li> </ul></td> </tr></table> </div> </div> <footer> <hr/> <div role="contentinfo"> <p>© Copyright 2020, Jeremy Avigad, Kevin Buzzard, Robert Y. Lewis, Patrick Massot.</p> </div> Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. </footer> </div> </div> </section> </div> <script> jQuery(function () { SphinxRtdTheme.Navigation.enable(true); }); </script> </body> </html>
-
-
html/index.html (new)
-
@@ -0,0 +1,182 @@<!DOCTYPE html> <html class="writer-html5" lang="en" > <head> <meta charset="utf-8" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Mathematics in Lean — Mathematics in Lean 0.1 documentation</title> <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> <link rel="stylesheet" href="_static/css/custom.css" type="text/css" /> <link rel="shortcut icon" href="_static/favicon.ico"/> <!--[if lt IE 9]> <script src="_static/js/html5shiv.min.js"></script> <![endif]--> <script src="_static/jquery.js"></script> <script src="_static/_sphinx_javascript_frameworks_compat.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script src="_static/doctools.js"></script> <script src="_static/sphinx_highlight.js"></script> <script src="_static/js/theme.js"></script> <link rel="index" title="Index" href="genindex.html" /> <link rel="search" title="Search" href="search.html" /> <link rel="next" title="1. Introduction" href="C01_Introduction.html" /> </head> <body class="wy-body-for-nav"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search" > <a href="#" class="icon icon-home"> Mathematics in Lean </a> <div role="search"> <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> <ul> <li class="toctree-l1"><a class="reference internal" href="C01_Introduction.html">1. Introduction</a></li> <li class="toctree-l1"><a class="reference internal" href="C02_Basics.html">2. Basics</a></li> <li class="toctree-l1"><a class="reference internal" href="C03_Logic.html">3. Logic</a></li> <li class="toctree-l1"><a class="reference internal" href="C04_Sets_and_Functions.html">4. Sets and Functions</a></li> <li class="toctree-l1"><a class="reference internal" href="C05_Number_Theory.html">5. Number Theory</a></li> <li class="toctree-l1"><a class="reference internal" href="C06_Structures.html">6. Structures</a></li> <li class="toctree-l1"><a class="reference internal" href="C07_Hierarchies.html">7. Hierarchies</a></li> <li class="toctree-l1"><a class="reference internal" href="C08_Topology.html">8. Topology</a></li> <li class="toctree-l1"><a class="reference internal" href="C09_Differential_Calculus.html">9. Differential Calculus</a></li> </ul> <ul> <li class="toctree-l1"><a class="reference internal" href="genindex.html">Index</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="#">Mathematics in Lean</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="Page navigation"> <ul class="wy-breadcrumbs"> <li><a href="#" class="icon icon-home" aria-label="Home"></a></li> <li class="breadcrumb-item active">Mathematics in Lean</li> <li class="wy-breadcrumbs-aside"> <a href="_sources/index.rst.txt" rel="nofollow"> View page source</a> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <section id="mathematics-in-lean"> <h1>Mathematics in Lean<a class="headerlink" href="#mathematics-in-lean" title="Permalink to this heading"></a></h1> <div class="toctree-wrapper compound"> <ul> <li class="toctree-l1"><a class="reference internal" href="C01_Introduction.html">1. Introduction</a><ul> <li class="toctree-l2"><a class="reference internal" href="C01_Introduction.html#getting-started">1.1. Getting Started</a></li> <li class="toctree-l2"><a class="reference internal" href="C01_Introduction.html#overview">1.2. Overview</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="C02_Basics.html">2. Basics</a><ul> <li class="toctree-l2"><a class="reference internal" href="C02_Basics.html#calculating">2.1. Calculating</a></li> <li class="toctree-l2"><a class="reference internal" href="C02_Basics.html#proving-identities-in-algebraic-structures">2.2. Proving Identities in Algebraic Structures</a></li> <li class="toctree-l2"><a class="reference internal" href="C02_Basics.html#using-theorems-and-lemmas">2.3. Using Theorems and Lemmas</a></li> <li class="toctree-l2"><a class="reference internal" href="C02_Basics.html#more-on-order-and-divisibility">2.4. More on Order and Divisibility</a></li> <li class="toctree-l2"><a class="reference internal" href="C02_Basics.html#proving-facts-about-algebraic-structures">2.5. Proving Facts about Algebraic Structures</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="C03_Logic.html">3. Logic</a><ul> <li class="toctree-l2"><a class="reference internal" href="C03_Logic.html#implication-and-the-universal-quantifier">3.1. Implication and the Universal Quantifier</a></li> <li class="toctree-l2"><a class="reference internal" href="C03_Logic.html#the-existential-quantifier">3.2. The Existential Quantifier</a></li> <li class="toctree-l2"><a class="reference internal" href="C03_Logic.html#negation">3.3. Negation</a></li> <li class="toctree-l2"><a class="reference internal" href="C03_Logic.html#conjunction-and-bi-implication">3.4. Conjunction and Bi-implication</a></li> <li class="toctree-l2"><a class="reference internal" href="C03_Logic.html#disjunction">3.5. Disjunction</a></li> <li class="toctree-l2"><a class="reference internal" href="C03_Logic.html#sequences-and-convergence">3.6. Sequences and Convergence</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="C04_Sets_and_Functions.html">4. Sets and Functions</a><ul> <li class="toctree-l2"><a class="reference internal" href="C04_Sets_and_Functions.html#sets">4.1. Sets</a></li> <li class="toctree-l2"><a class="reference internal" href="C04_Sets_and_Functions.html#functions">4.2. Functions</a></li> <li class="toctree-l2"><a class="reference internal" href="C04_Sets_and_Functions.html#the-schroder-bernstein-theorem">4.3. The Schröder-Bernstein Theorem</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="C05_Number_Theory.html">5. Number Theory</a><ul> <li class="toctree-l2"><a class="reference internal" href="C05_Number_Theory.html#irrational-roots">5.1. Irrational Roots</a></li> <li class="toctree-l2"><a class="reference internal" href="C05_Number_Theory.html#induction-and-recursion">5.2. Induction and Recursion</a></li> <li class="toctree-l2"><a class="reference internal" href="C05_Number_Theory.html#infinitely-many-primes">5.3. Infinitely Many Primes</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="C06_Structures.html">6. Structures</a><ul> <li class="toctree-l2"><a class="reference internal" href="C06_Structures.html#defining-structures">6.1. Defining structures</a></li> <li class="toctree-l2"><a class="reference internal" href="C06_Structures.html#algebraic-structures">6.2. Algebraic Structures</a></li> <li class="toctree-l2"><a class="reference internal" href="C06_Structures.html#building-the-gaussian-integers">6.3. Building the Gaussian Integers</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="C07_Hierarchies.html">7. Hierarchies</a><ul> <li class="toctree-l2"><a class="reference internal" href="C07_Hierarchies.html#basics">7.1. Basics</a></li> <li class="toctree-l2"><a class="reference internal" href="C07_Hierarchies.html#morphisms">7.2. Morphisms</a></li> <li class="toctree-l2"><a class="reference internal" href="C07_Hierarchies.html#sub-objects">7.3. Sub-objects</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="C08_Topology.html">8. Topology</a><ul> <li class="toctree-l2"><a class="reference internal" href="C08_Topology.html#filters">8.1. Filters</a></li> <li class="toctree-l2"><a class="reference internal" href="C08_Topology.html#metric-spaces">8.2. Metric spaces</a></li> <li class="toctree-l2"><a class="reference internal" href="C08_Topology.html#topological-spaces">8.3. Topological spaces</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="C09_Differential_Calculus.html">9. Differential Calculus</a><ul> <li class="toctree-l2"><a class="reference internal" href="C09_Differential_Calculus.html#elementary-differential-calculus">9.1. Elementary Differential Calculus</a></li> <li class="toctree-l2"><a class="reference internal" href="C09_Differential_Calculus.html#differential-calculus-in-normed-spaces">9.2. Differential Calculus in Normed Spaces</a></li> </ul> </li> </ul> </div> <div class="toctree-wrapper compound"> </div> </section> </div> </div> <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> <a href="C01_Introduction.html" class="btn btn-neutral float-right" title="1. Introduction" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> </div> <hr/> <div role="contentinfo"> <p>© Copyright 2020, Jeremy Avigad, Kevin Buzzard, Robert Y. Lewis, Patrick Massot.</p> </div> Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. </footer> </div> </div> </section> </div> <script> jQuery(function () { SphinxRtdTheme.Navigation.enable(true); }); </script> </body> </html>
-
-
html/objects.inv (new)
-
html/search.html (new)
-
@@ -0,0 +1,132 @@<!DOCTYPE html> <html class="writer-html5" lang="en" > <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Search — Mathematics in Lean 0.1 documentation</title> <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> <link rel="stylesheet" href="_static/css/custom.css" type="text/css" /> <link rel="shortcut icon" href="_static/favicon.ico"/> <!--[if lt IE 9]> <script src="_static/js/html5shiv.min.js"></script> <![endif]--> <script src="_static/jquery.js"></script> <script src="_static/_sphinx_javascript_frameworks_compat.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script src="_static/doctools.js"></script> <script src="_static/sphinx_highlight.js"></script> <script src="_static/js/theme.js"></script> <script src="_static/searchtools.js"></script> <script src="_static/language_data.js"></script> <link rel="index" title="Index" href="genindex.html" /> <link rel="search" title="Search" href="#" /> </head> <body class="wy-body-for-nav"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search" > <a href="index.html" class="icon icon-home"> Mathematics in Lean </a> <div role="search"> <form id="rtd-search-form" class="wy-form" action="#" method="get"> <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> <ul> <li class="toctree-l1"><a class="reference internal" href="C01_Introduction.html">1. Introduction</a></li> <li class="toctree-l1"><a class="reference internal" href="C02_Basics.html">2. Basics</a></li> <li class="toctree-l1"><a class="reference internal" href="C03_Logic.html">3. Logic</a></li> <li class="toctree-l1"><a class="reference internal" href="C04_Sets_and_Functions.html">4. Sets and Functions</a></li> <li class="toctree-l1"><a class="reference internal" href="C05_Number_Theory.html">5. Number Theory</a></li> <li class="toctree-l1"><a class="reference internal" href="C06_Structures.html">6. Structures</a></li> <li class="toctree-l1"><a class="reference internal" href="C07_Hierarchies.html">7. Hierarchies</a></li> <li class="toctree-l1"><a class="reference internal" href="C08_Topology.html">8. Topology</a></li> <li class="toctree-l1"><a class="reference internal" href="C09_Differential_Calculus.html">9. Differential Calculus</a></li> </ul> <ul> <li class="toctree-l1"><a class="reference internal" href="genindex.html">Index</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="index.html">Mathematics in Lean</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="Page navigation"> <ul class="wy-breadcrumbs"> <li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li> <li class="breadcrumb-item active">Search</li> <li class="wy-breadcrumbs-aside"> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <noscript> <div id="fallback" class="admonition warning"> <p class="last"> Please activate JavaScript to enable the search functionality. </p> </div> </noscript> <div id="search-results"> </div> </div> </div> <footer> <hr/> <div role="contentinfo"> <p>© Copyright 2020, Jeremy Avigad, Kevin Buzzard, Robert Y. Lewis, Patrick Massot.</p> </div> Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. </footer> </div> </div> </section> </div> <script> jQuery(function () { SphinxRtdTheme.Navigation.enable(true); }); </script> <script> jQuery(function() { Search.loadIndex("searchindex.js"); }); </script> <script id="searchindexloader"></script> </body> </html>
-
-
html/searchindex.js (new)
-
@@ -0,0 +1,1 @@Search.setIndex({"docnames": ["C01_Introduction", "C02_Basics", "C03_Logic", "C04_Sets_and_Functions", "C05_Number_Theory", "C06_Structures", "C07_Hierarchies", "C08_Topology", "C09_Differential_Calculus", "C10_Integration_and_Measure_Theory", "genindex", "index"], "filenames": ["C01_Introduction.rst", "C02_Basics.rst", "C03_Logic.rst", "C04_Sets_and_Functions.rst", "C05_Number_Theory.rst", "C06_Structures.rst", "C07_Hierarchies.rst", "C08_Topology.rst", "C09_Differential_Calculus.rst", "C10_Integration_and_Measure_Theory.rst", "genindex.rst", "index.rst"], "titles": ["<span class=\"section-number\">1. </span>Introduction", "<span class=\"section-number\">2. </span>Basics", "<span class=\"section-number\">3. </span>Logic", "<span class=\"section-number\">4. </span>Sets and Functions", "<span class=\"section-number\">5. </span>Number Theory", "<span class=\"section-number\">6. </span>Structures", "<span class=\"section-number\">7. </span>Hierarchies", "<span class=\"section-number\">8. </span>Topology", "<span class=\"section-number\">9. </span>Differential Calculus", "Integration and Measure Theory", "Index", "Mathematics in Lean"], "terms": {"The": [0, 1, 4, 5, 6, 7, 8, 11], "goal": [0, 1, 2, 3, 4, 5, 7], "thi": [0, 1, 2, 3, 4, 5, 6, 7, 8], "book": [0, 7], "i": [0, 1, 2, 3, 4, 5, 6, 7, 8], "teach": 0, "you": [0, 1, 2, 3, 4, 5, 6, 7, 8], "formal": [0, 1, 2, 3, 4, 5, 6, 7, 8], "mathemat": [0, 1, 2, 3, 4, 5, 6, 7], "us": [0, 2, 3, 4, 5, 6, 7, 8, 11], "lean": [0, 1, 2, 3, 4, 5, 6, 7, 8], "4": [0, 1, 2, 4, 5, 7, 8], "interact": [0, 5, 6], "proof": [0, 1, 2, 3, 4, 5, 6, 7, 8], "assist": [0, 5], "It": [0, 1, 2, 3, 4, 5, 6, 7, 8], "assum": [0, 1, 2, 3, 4, 6, 7], "know": [0, 1, 2, 3, 4, 5, 6, 7, 8], "some": [0, 1, 2, 3, 4, 5, 6, 7, 8], "doe": [0, 1, 2, 3, 4, 5, 6, 7, 8], "requir": [0, 1, 2, 3, 4, 5, 6, 7, 8], "much": [0, 2, 4, 6, 7, 8], "although": [0, 3, 4, 5, 6, 7], "we": [0, 1, 2, 3, 4, 5, 6, 7, 8], "cover": [0, 1, 3, 6, 7, 8], "exampl": [0, 1, 2, 3, 4, 5, 6, 7, 8], "rang": [0, 2, 3, 4, 7], "from": [0, 1, 2, 3, 4, 5, 6, 7, 8], "number": [0, 1, 2, 3, 5, 6, 7, 8, 11], "theori": [0, 1, 2, 3, 6, 7, 8, 11], "measur": [0, 5, 7, 8], "analysi": [0, 5, 8], "focu": [0, 1, 7], "elementari": [0, 3, 4, 5, 7, 11], "aspect": [0, 5], "those": [0, 1, 2, 3, 5, 6, 7, 8], "field": [0, 1, 5, 6, 8], "hope": 0, "thei": [0, 1, 2, 3, 4, 5, 6, 7, 8], "ar": [0, 1, 2, 3, 4, 5, 6, 7, 8], "familiar": [0, 1, 4, 5, 7, 8], "can": [0, 1, 2, 3, 4, 5, 6, 7, 8], "pick": [0, 6], "them": [0, 1, 2, 3, 4, 5, 6, 7], "up": [0, 2, 3, 4, 5, 6, 7], "go": [0, 1, 2, 3, 4, 6, 7], "also": [0, 1, 2, 3, 4, 5, 6, 7, 8], "don": [0, 1, 2, 3, 4, 5, 6, 7], "t": [0, 1, 2, 3, 4, 5, 6, 7], "presuppos": 0, "ani": [0, 1, 2, 3, 4, 5, 6, 7, 8], "background": 0, "seen": [0, 1, 2, 4, 5, 6, 7], "kind": [0, 1, 6, 7], "comput": [0, 3, 4, 5, 8], "program": [0, 1], "write": [0, 1, 2, 3, 4, 5, 6, 7, 8], "definit": [0, 1, 2, 3, 4, 5, 6, 7, 8], "theorem": [0, 2, 4, 5, 7, 8, 11], "regiment": 0, "languag": [0, 1, 3], "like": [0, 1, 2, 3, 4, 5, 6, 7], "understand": [0, 2, 3, 4, 5, 6, 7], "In": [0, 1, 2, 3, 4, 5, 6, 7, 8], "return": [0, 2, 3, 4, 5, 7], "provid": [0, 1, 2, 3, 4, 5, 6, 7, 8], "feedback": 0, "inform": [0, 1, 2, 3, 5, 6, 7], "interpret": [0, 1, 4, 5, 7], "express": [0, 1, 2, 3, 4, 5, 6, 7, 8], "guarante": [0, 3, 5], "well": [0, 1, 2, 3, 4, 5, 6, 7], "form": [0, 1, 2, 3, 4, 5, 6, 7], "ultim": 0, "certifi": 0, "correct": [0, 1], "our": [0, 1, 2, 3, 4, 5, 6, 7], "learn": [0, 1, 2, 4, 5], "more": [0, 2, 3, 4, 5, 6, 7, 8, 11], "about": [0, 2, 3, 4, 5, 6, 7, 8, 11], "project": [0, 4, 5, 7], "page": [0, 1, 4], "commun": [0, 4], "web": [0, 1, 4], "tutori": 0, "base": [0, 3, 4, 6, 7, 8], "": [0, 1, 2, 3, 4, 5, 6, 7, 8], "larg": [0, 6, 7], "ever": [0, 7], "grow": [0, 6], "librari": [0, 1, 2, 3, 4, 5, 7, 8], "mathlib": [0, 1, 2, 3, 4, 5, 6, 7, 8], "strongli": 0, "recommend": [0, 1, 3], "take": [0, 1, 2, 3, 4, 5, 6, 7, 8], "look": [0, 1, 2, 3, 4, 6, 7], "zulip": [0, 4], "onlin": 0, "chat": 0, "group": [0, 1, 2, 3, 5, 6, 7, 8], "haven": [0, 2, 6, 7], "alreadi": [0, 1, 2, 3, 4, 5, 6, 7], "ll": [0, 2, 4, 6, 7], "find": [0, 1, 2, 4, 5, 6, 7], "live": [0, 5], "welcom": [0, 1], "enthusiast": 0, "happi": 0, "answer": [0, 5, 7], "question": [0, 4, 6, 7], "offer": [0, 2, 5, 7], "moral": [0, 5], "support": [0, 1, 2, 3, 4, 5, 6, 7], "read": [0, 1, 4, 6, 7], "pdf": 0, "html": 0, "version": [0, 1, 2, 3, 4, 5, 6, 7, 8], "design": [0, 1, 2, 3, 5, 7], "run": 0, "insid": [0, 1, 2, 3], "v": [0, 1, 2, 3, 5, 7], "code": [0, 1, 2, 3, 5, 6], "editor": [0, 1], "To": [0, 1, 2, 3, 4, 5, 6, 7], "instal": [0, 6], "follow": [0, 1, 2, 3, 4, 5, 6, 7, 8], "instruct": [0, 1, 7], "termin": 0, "navig": 0, "folder": 0, "where": [0, 1, 2, 3, 4, 5, 6, 7, 8], "want": [0, 1, 2, 3, 4, 5, 6, 7, 8], "put": [0, 1, 2, 3, 4, 5, 6, 7], "copi": [0, 3, 4, 6, 7], "repositori": [0, 1], "type": [0, 1, 2, 3, 4, 5, 6, 7, 8], "git": 0, "clone": 0, "github": [0, 1], "com": 0, "leanprov": 0, "mathematics_in_lean": 0, "fetch": 0, "execut": 0, "lake": 0, "ex": [0, 2], "cach": 0, "compil": 0, "open": [0, 1, 2, 3, 4, 5, 8], "altern": [0, 2, 3, 4, 5, 6, 7], "choos": [0, 2, 3, 4, 5, 6, 7], "file": [0, 1, 4, 5, 6, 7], "menu": [0, 1], "Be": [0, 1, 3], "sure": [0, 1, 2, 3, 5, 6], "other": [0, 1, 2, 3, 4, 5, 6, 7], "simultan": 0, "window": [0, 1, 2, 5], "updat": 0, "newer": 0, "ty": 0, "pull": [0, 7], "cloud": 0, "gitpod": 0, "how": [0, 1, 2, 3, 4, 5, 6, 7], "do": [0, 1, 2, 3, 4, 5, 6, 7, 8], "each": [0, 1, 2, 3, 4, 5, 6, 7, 8], "section": [0, 1, 2, 3, 4, 5, 6, 7, 8], "ha": [0, 1, 2, 3, 4, 5, 6, 7, 8], "an": [0, 1, 2, 3, 4, 5, 6, 7, 8], "associ": [0, 1, 2, 4, 5, 6, 7], "exercis": [0, 1, 2, 3, 5, 6, 7, 8], "mil": 0, "organ": 0, "chapter": [0, 1, 2, 3, 4, 5, 6, 7, 8], "make": [0, 1, 2, 3, 4, 5, 6, 7, 8], "so": [0, 1, 2, 3, 4, 5, 6, 7, 8], "experi": [0, 1, 7], "while": [0, 1, 2, 6, 7], "leav": [0, 1, 2, 3, 5, 6], "origin": [0, 1, 5], "intact": 0, "text": [0, 3, 5, 6, 7], "often": [0, 1, 2, 3, 4, 5, 6, 7], "includ": [0, 1, 2, 3, 4, 6, 7, 8], "one": [0, 1, 2, 3, 4, 5, 6, 7, 8], "eval": 0, "hello": 0, "world": 0, "should": [0, 1, 2, 3, 4, 5, 6, 7, 8], "abl": [0, 1, 2, 3, 4, 5, 6, 8], "correspond": [0, 1, 2, 3, 4, 5, 6, 7, 8], "If": [0, 1, 2, 3, 4, 5, 6, 7], "click": [0, 1, 3, 4, 5, 6], "line": [0, 1, 2, 3, 4, 6], "show": [0, 1, 2, 3, 4, 5, 6, 7, 8], "hover": [0, 1, 2, 3, 4, 5], "your": [0, 1, 2, 3, 5, 6, 7], "cursor": [0, 1, 2], "over": [0, 1, 2, 3, 4, 5, 6, 7, 8], "command": [0, 1, 2, 3, 4, 5, 6], "respons": [0, 1], "pop": 0, "encourag": [0, 1, 2, 3, 4, 5], "edit": 0, "try": [0, 1, 2, 3, 4, 5, 6, 7], "own": [0, 1, 4, 5, 6], "moreov": [0, 1, 4, 5, 7], "lot": [0, 3, 5, 6, 7], "challeng": [0, 1, 2, 3, 5, 8], "rush": 0, "past": [0, 1], "just": [0, 1, 2, 3, 4, 5, 6, 7], "work": [0, 1, 2, 3, 4, 5, 6, 7, 8], "through": [0, 1, 3, 4, 5, 6, 7], "central": [0, 4], "alwai": [0, 1, 2, 3, 5, 6], "compar": [0, 5, 6, 7], "solut": [0, 1, 4, 6], "ones": [0, 1, 2, 3, 5], "simpli": [0, 1, 2, 3, 4, 5, 6, 7], "tool": [0, 1, 2, 5, 6], "build": [0, 2, 4, 6, 7, 11], "complex": [0, 1, 2, 4, 5, 8], "known": [0, 1, 2, 3, 4, 5, 6, 7, 8], "depend": [0, 2, 3, 4, 5, 6, 7], "everi": [0, 1, 2, 3, 4, 5, 6, 7, 8], "check": [0, 1, 2, 3, 4, 5, 6, 7], "print": [0, 3, 4, 5], "have": [0, 1, 2, 3, 4, 5, 6, 7, 8], "\u2115": [0, 1, 2, 3, 4, 5, 6, 7, 8], "These": [0, 1, 2, 3, 4, 5, 8], "object": [0, 1, 2, 3, 4, 5, 11], "2": [0, 1, 2, 3, 4, 5, 6, 7, 8], "def": [0, 2, 3, 4, 5, 6, 7], "f": [0, 1, 2, 3, 4, 5, 6, 7, 8], "x": [0, 1, 2, 3, 4, 5, 6, 7, 8], "3": [0, 1, 2, 3, 4, 5, 6, 7], "prop": [0, 2, 3, 4, 5, 6, 7], "statement": [0, 1, 2, 3, 4, 5, 6, 7, 8], "fermatlasttheorem": 0, "y": [0, 1, 2, 3, 4, 5, 6, 7, 8], "z": [0, 1, 2, 5, 6, 7, 8], "n": [0, 1, 2, 3, 4, 5, 6, 7, 8], "0": [0, 1, 2, 3, 4, 5, 6, 7, 8], "p": [0, 1, 2, 3, 4, 5, 6, 7], "itself": [0, 3, 5, 6, 7, 8], "Such": [0, 1, 2, 6], "proposit": [0, 2, 3, 4, 5], "easi": [0, 4, 5, 6, 7], "rfl": [0, 1, 2, 3, 4, 5, 6, 7, 8], "hard": [0, 1, 3, 5, 6], "sorri": [0, 1, 2, 3, 4, 5, 6, 7, 8], "manag": [0, 1, 4, 5, 7], "construct": [0, 2, 3, 4, 5, 6, 7], "fermat_last_theorem": 0, "accept": [0, 1, 7], "term": [0, 1, 2, 3, 4, 5, 7], "done": [0, 2, 3, 4, 6, 7], "someth": [0, 1, 2, 4, 6, 7], "veri": [0, 2, 4, 6, 7], "impress": 0, "cheat": [0, 1], "now": [0, 1, 2, 3, 4, 5, 6, 7, 8], "game": [0, 6], "all": [0, 1, 2, 3, 4, 5, 6, 7, 8], "left": [0, 1, 2, 3, 4, 5, 6, 7, 8], "rule": [0, 2, 4, 5, 6, 7], "complementari": 0, "companion": [0, 1], "prove": [0, 2, 3, 4, 5, 6, 7, 8, 11], "which": [0, 1, 2, 3, 4, 5, 6, 7, 8], "thorough": 0, "underli": [0, 1, 5, 6], "logic": [0, 1, 3, 4, 5, 11], "framework": 0, "core": [0, 4, 5], "syntax": [0, 1, 3, 4, 6], "peopl": [0, 1], "who": [0, 7], "prefer": [0, 1, 3], "user": [0, 2, 6], "manual": [0, 3, 4], "befor": [0, 1, 2, 3, 4, 5, 6], "new": [0, 1, 2, 3, 4, 5, 6, 7], "dishwash": 0, "person": 0, "hit": [0, 1], "button": 0, "figur": [0, 1, 2, 5], "out": [0, 1, 2, 3, 4, 5, 6, 7], "activ": 0, "potscrubb": 0, "featur": [0, 2, 4], "later": [0, 1, 2, 4, 5, 6, 7], "sens": [0, 2, 3, 4, 5, 6, 7, 8], "here": [0, 1, 2, 3, 4, 5, 6, 7, 8], "refer": [0, 1, 2, 4, 5, 6, 7, 8], "back": [0, 1, 2, 3, 5, 6, 7], "necessari": [0, 2, 4, 5], "anoth": [0, 1, 2, 3, 4, 5, 6, 7], "thing": [0, 1, 2, 3, 4, 5, 6, 7], "distinguish": [0, 5, 6, 7, 8], "place": [0, 1, 2, 5, 7], "greater": [0, 1, 2, 3, 4, 7], "emphasi": [0, 6], "tactic": [0, 1, 2, 3, 4, 5, 6, 7, 8], "given": [0, 1, 2, 3, 4, 5, 6, 7], "two": [0, 1, 2, 3, 4, 5, 6, 7], "wai": [0, 1, 2, 3, 4, 5, 6, 7], "down": [0, 3, 4, 6, 7], "themselv": [0, 4, 5], "suitabl": [0, 1, 2, 5, 7], "descript": [0, 1, 2, 4, 7], "thereof": 0, "For": [0, 1, 2, 3, 4, 5, 6, 7, 8], "repres": [0, 1, 2, 3, 4, 5, 6, 8], "fact": [0, 2, 3, 4, 5, 6, 7, 8, 11], "even": [0, 1, 2, 3, 4, 5, 6, 7, 8], "m": [0, 1, 2, 4, 6, 7, 8], "nat": [0, 1, 2, 3, 4, 5, 7], "fun": [0, 2, 3, 4, 5, 6, 7, 8], "k": [0, 2, 4, 5, 7, 8], "hk": [0, 8], "hmn": 0, "rw": [0, 1, 2, 3, 4, 5, 6, 7], "mul_add": [0, 1, 4, 6], "l": [0, 1, 8], "_": [0, 1, 2, 3, 4, 5, 6, 7, 8], "compress": [0, 1, 7], "singl": [0, 1, 2, 3, 4, 5, 6, 8], "instead": [0, 1, 2, 3, 4, 5, 6, 7], "style": [0, 1], "same": [0, 1, 2, 3, 4, 5, 6, 7], "sai": [0, 1, 2, 3, 4, 5, 6, 7], "natur": [0, 1, 2, 3, 4, 5, 6, 7, 8], "rintro": [0, 2, 3, 4, 5, 7], "need": [0, 1, 2, 3, 4, 5, 6, 7], "twice": [0, 7], "let": [0, 1, 2, 3, 4, 5, 6, 7, 8], "substitut": [0, 2], "obviou": [0, 4, 5, 6], "ring": [0, 1, 2, 3, 4, 5, 6], "As": [0, 1, 2, 3, 4, 5, 6, 7, 8], "enter": [0, 1, 2, 3, 7], "displai": [0, 2, 6], "state": [0, 1, 2, 3, 4, 6, 7, 8], "separ": [0, 1, 2, 4, 5], "tell": [0, 2, 3, 4, 5, 6], "what": [0, 1, 2, 3, 4, 5, 6, 7], "establish": [0, 1, 2, 3, 4, 5], "task": [0, 2, 4, 5, 6, 7], "remain": [0, 1, 2, 3, 5, 6, 7], "replai": 0, "step": [0, 1, 2, 3, 4, 5, 6], "sinc": [0, 1, 2, 3, 4, 5, 6, 7], "continu": [0, 1, 4, 5, 6], "point": [0, 1, 2, 3, 5, 6, 7, 8], "see": [0, 1, 2, 3, 4, 5, 6, 7, 8], "first": [0, 1, 2, 3, 4, 5, 6, 7, 8], "introduc": [0, 1, 2, 3, 4, 7], "could": [0, 1, 2, 4, 5, 6, 7], "renam": 0, "decompos": [0, 3, 5], "hypothesi": [0, 1, 2, 3, 4], "assumpt": [0, 1, 2, 3, 4, 5, 7, 8], "second": [0, 1, 2, 3, 4, 5, 6, 7], "declar": [0, 1, 4, 5, 6], "next": [0, 1, 2, 3, 4, 5, 6, 7, 8], "rewrit": [0, 1, 2, 3, 4, 5, 6, 7], "replac": [0, 1, 2, 3, 4, 6], "solv": [0, 1, 2, 3, 4, 5, 6, 7], "result": [0, 1, 2, 3, 4, 5, 6, 7], "abil": 0, "small": [0, 4, 5, 7], "increment": [0, 1], "extrem": [0, 6, 7], "power": [0, 2, 3, 4, 5, 6], "reason": [0, 1, 2, 4, 5, 6, 7], "easier": [0, 1, 3, 4, 6, 7], "quicker": 0, "than": [0, 1, 2, 3, 4, 5, 6, 7, 8], "There": [0, 1, 2, 3, 4, 6, 7, 8], "isn": [0, 2, 3, 4, 6], "sharp": 0, "distinct": [0, 2, 3, 4, 5, 7], "between": [0, 1, 2, 3, 4, 5, 6, 7, 8], "insert": [0, 2, 4, 5, 7, 8], "did": [0, 2, 6, 7], "phrase": [0, 1, 2, 4, 5], "mul_left_comm": [0, 4], "abov": [0, 1, 2, 3, 4, 5, 6, 7], "convers": [0, 2, 4, 7], "short": [0, 1, 2, 3, 4, 5], "middl": [0, 1, 2, 7], "That": [0, 4, 5, 6], "said": [0, 2, 4, 5], "reduc": [0, 2, 3, 4, 5], "liner": 0, "carri": [0, 1, 2, 3, 4, 5, 6, 7], "But": [0, 1, 2, 3, 4, 5, 6, 7], "substanti": 0, "autom": [0, 1, 5], "justifi": [0, 1, 2, 7], "longer": [0, 4, 5], "calcul": [0, 2, 4, 5, 11], "bigger": [0, 3, 8], "inferenti": 0, "invok": [0, 1, 7], "simplifi": [0, 2, 3, 4, 5, 7], "specif": [0, 1, 3, 4, 5, 6], "pariti": [0, 4], "automat": [0, 1, 2, 3, 4, 5, 6, 7, 8], "intro": [0, 1, 2, 3, 4, 5, 6, 7], "simp": [0, 2, 3, 4, 5, 6, 7, 8], "parity_simp": 0, "big": [0, 5, 7, 8], "differ": [0, 1, 2, 3, 4, 5, 6, 7, 8], "onli": [0, 1, 2, 3, 4, 5, 6, 7, 8], "its": [0, 1, 2, 3, 4, 5, 6, 7, 8], "built": [0, 2, 6], "wherea": [0, 1, 3, 5, 7], "top": [0, 6, 7, 8], "meant": [0, 2, 6], "contain": [0, 2, 3, 4, 5, 6, 7, 8], "extens": [0, 1, 6, 7, 8], "document": [0, 1, 3, 4, 6], "rather": [0, 1, 2, 4, 5, 6, 7], "think": [0, 1, 2, 3, 4, 5, 6, 7, 8], "comfort": [0, 2], "brows": [0, 1, 4], "frustrat": [0, 6], "curv": 0, "steep": 0, "newcom": 0, "avail": [0, 1, 4, 5, 6], "round": [0, 1, 5], "clock": 0, "doubt": 0, "soon": [0, 2, 6, 7], "enough": [0, 1, 2, 3, 4, 6, 7], "too": [0, 1, 3, 5, 6, 7], "contribut": [0, 3], "develop": [0, 1, 4], "mission": 0, "dive": 0, "come": [0, 1, 2, 3, 4, 5, 6, 7], "forewarn": 0, "fundament": [0, 4, 5, 6], "life": [0, 2], "mai": [0, 1, 2, 3, 5, 6, 7, 8], "never": [0, 6], "acknowledg": 0, "grate": [0, 5], "gabriel": 0, "ebner": 0, "set": [0, 1, 2, 4, 5, 6, 8, 11], "infrastructur": 0, "scott": 0, "morrison": 0, "mario": 0, "carneiro": 0, "help": [0, 1, 2, 3, 4, 5, 6, 7], "port": 0, "bryan": 0, "gin": 0, "ge": [0, 2, 5], "chen": 0, "johan": 0, "commelin": 0, "mathieu": 0, "guai": 0, "paquet": 0, "julian": 0, "k\u00fclshammer": 0, "giovanni": 0, "mascellani": 0, "hunter": 0, "monro": 0, "pietro": 0, "monticon": 0, "bartosz": 0, "piotrowski": 0, "guilherm": 0, "silva": 0, "been": [0, 1, 2, 4, 5, 6, 8], "partial": [0, 1, 2, 3, 5, 6], "hoskinson": 0, "center": [0, 7], "nut": 1, "bolt": 1, "appli": [1, 2, 3, 4, 5, 6, 7, 8], "gener": [1, 2, 3, 4, 5, 6, 7, 8], "without": [1, 2, 4, 5, 6, 7, 8], "when": [1, 2, 3, 4, 5, 6, 7, 8], "u": [1, 2, 3, 4, 5, 6, 7, 8], "net": 1, "hand": [1, 2, 3, 4, 5, 6, 7], "side": [1, 2, 3, 4, 5, 6, 7, 8], "equal": [1, 2, 3, 4, 5, 6, 7], "right": [1, 2, 3, 4, 5, 6, 7, 8], "tantamount": [1, 3], "name": [1, 2, 3, 4, 5, 6, 7, 8], "b": [1, 2, 3, 4, 5, 6, 7, 8], "c": [1, 2, 4, 5, 6, 7, 8], "real": [1, 2, 3, 4, 5, 6, 7, 8], "mul_assoc": [1, 2, 4, 5, 6], "mul_comm": [1, 2, 4, 5, 6], "elimin": 1, "explicitli": [1, 2, 3, 5, 6, 7, 8], "purpos": [1, 2, 3, 4, 5, 6, 7], "illustr": [1, 2, 3, 4, 5], "multipl": [1, 2, 3, 4, 5, 6, 8], "written": [1, 2, 3, 4, 5, 6, 7, 8], "howev": [1, 2, 5, 6, 7, 8], "good": [1, 2, 3, 4, 5, 6, 7], "mind": [1, 2, 5, 6], "notat": [1, 2, 3, 4, 5, 6, 7, 8], "convent": [1, 5], "parenthes": [1, 2, 3, 4], "\u211d": [1, 2, 3, 5, 6, 7, 8], "import": [1, 2, 3, 4, 5, 6, 7], "begin": [1, 2, 3, 4, 5, 6], "sake": [1, 4], "breviti": [1, 5], "suppress": 1, "repeat": [1, 4, 5, 6], "chang": [1, 2, 4, 5, 7], "happen": [1, 6, 7], "charact": [1, 3, 6], "r": [1, 2, 4, 5, 6, 7], "symbol": [1, 2, 5, 6], "doesn": [1, 2, 7], "appear": [1, 2, 5, 6, 7], "until": [1, 2, 4, 5, 6, 7], "space": [1, 3, 5, 6, 11], "tab": [1, 2, 3, 4], "kei": [1, 4, 5, 7], "curiou": [1, 6], "abrevi": 1, "ctrl": [1, 4, 5], "shift": [1, 6, 7], "abbrevi": [1, 2, 3, 5], "get": [1, 2, 3, 4, 6, 7, 8, 11], "access": [1, 3, 5, 6, 7], "keyboard": 1, "easili": [1, 4, 5, 6], "backslash": [1, 3], "lead": [1, 2, 4, 5, 6, 7], "input": [1, 3, 7], "leader": 1, "report": 1, "current": [1, 2, 6], "infoview": 1, "move": [1, 2, 6, 7], "A": [1, 2, 3, 4, 5, 6, 7, 8], "typic": 1, "might": [1, 2, 3, 4, 5], "1": [1, 2, 3, 4, 5, 6, 7, 8], "h\u2081": [1, 2, 3, 4], "prime": [1, 2, 3, 5, 6, 11], "h\u2082": [1, 3, 4], "h\u2083": [1, 3], "denot": [1, 3, 4, 6, 7], "context": [1, 2, 4, 5, 6, 7, 8], "plai": [1, 3, 4, 6, 7], "three": [1, 2, 4, 5, 7], "label": [1, 2], "everyth": [1, 2, 6, 7], "identifi": [1, 2, 4], "subscript": 1, "h": [1, 2, 3, 4, 5, 6, 7, 8], "legal": 1, "would": [1, 2, 3, 4, 5, 6, 7, 8], "h1": [1, 3, 4, 5], "h2": [1, 3, 5], "h3": 1, "foo": [1, 3, 5], "bar": [1, 2], "baz": 1, "last": [1, 2, 3, 4, 5, 6, 7], "sometim": [1, 2, 3, 4, 5, 6, 7], "target": [1, 6, 7], "combin": [1, 2, 5, 6, 7], "practic": [1, 2, 3, 6, 7], "intend": [1, 2, 5], "mean": [1, 2, 3, 4, 5, 6, 7, 8], "usual": [1, 2, 3, 4, 5, 7], "clear": [1, 2, 4, 5, 6], "case": [1, 2, 3, 4, 5, 6, 7], "With": [1, 3, 4, 6, 7], "arrow": [1, 2, 6, 7], "revers": [1, 2, 3, 5, 7], "note": [1, 2, 4, 5, 6, 7], "noth": [1, 2, 3, 4, 5, 6], "argument": [1, 2, 3, 4, 5, 6, 7], "tri": [1, 2, 4, 6], "match": [1, 2, 5], "pattern": [1, 2, 3, 5, 6], "local": [1, 2, 6, 7, 8], "d": [1, 2, 4, 5, 8], "e": [1, 2, 3, 4, 5, 6, 7, 8], "sub_self": [1, 2], "hyp": 1, "list": [1, 2, 3, 4, 5], "relev": [1, 2, 4, 5, 6, 7], "comma": 1, "squar": [1, 2, 4, 5, 6], "bracket": [1, 2, 5, 6], "still": [1, 2, 3, 4, 5, 6, 7], "progress": [1, 5], "after": [1, 2, 4, 6, 7, 8], "trick": [1, 2, 4, 6, 8], "variabl": [1, 2, 3, 4, 5, 6, 7, 8], "onc": [1, 2, 3, 4, 5, 6, 7], "outsid": [1, 4], "g": [1, 2, 3, 5, 6, 7, 8], "inspect": 1, "reveal": 1, "inde": [1, 5, 6, 7, 8], "delimit": 1, "scope": [1, 2, 3, 5], "end": [1, 2, 3, 4, 5, 6, 7, 8], "block": [1, 4], "final": [1, 2, 3, 5, 7], "recal": [1, 2, 4, 5, 7], "introduct": [1, 2, 7, 11], "determin": [1, 5, 7], "both": [1, 2, 3, 4, 5, 6, 7, 8], "expect": [1, 2, 3, 4, 5, 6, 7], "rais": [1, 4], "error": [1, 2, 3, 6], "explain": [1, 2, 3, 4, 5, 6, 7], "output": 1, "meanwhil": [1, 4], "two_mul": 1, "add_mul": [1, 6], "distribut": [1, 4, 5, 6], "addit": [1, 2, 4, 5, 6, 7, 8], "add_assoc": [1, 4, 5, 6], "precis": [1, 3, 7, 8], "possibl": [1, 2, 3, 4, 5, 7], "calc": [1, 2, 3, 5, 7], "keyword": [1, 2, 4, 5], "notic": [1, 2, 3, 4, 5, 7], "finicki": 1, "dot": [1, 7], "underscor": [1, 2, 3], "justif": [1, 2], "format": 1, "indic": [1, 2, 3, 5, 6], "indent": 1, "One": [1, 2, 3, 4, 5, 6, 7], "outlin": [1, 2, 4, 7], "modulo": [1, 4, 5], "individu": 1, "pure": [1, 7], "littl": [1, 2, 7, 8], "underneath": [1, 3], "pow_two": [1, 4], "mul_sub": 1, "add_sub": 1, "sub_sub": 1, "add_zero": [1, 5, 6], "perform": [1, 2, 3], "exact": [1, 2, 3, 4, 5, 7], "becaus": [1, 2, 3, 4, 5, 6, 7, 8], "exactli": [1, 2, 3, 5, 6, 7], "close": [1, 2, 3, 6, 8], "bit": [1, 4, 6, 7], "commut": [1, 2, 3, 4, 5, 6, 8], "long": [1, 2, 3, 5, 6, 8], "axiom": [1, 3, 5, 6, 7], "indirectli": 1, "data": [1, 2, 4, 5, 6, 7], "similar": [1, 2, 3, 5, 6, 7], "common": [1, 2, 3, 4, 5, 7], "variat": [1, 3, 4, 5, 7, 8], "call": [1, 2, 3, 4, 5, 6, 7, 8], "nth_rewrit": 1, "allow": [1, 2, 3, 4, 5, 6, 7, 8], "particular": [1, 2, 5, 6, 7], "instanc": [1, 2, 3, 4, 5, 6, 7, 8], "enumer": [1, 2], "start": [1, 2, 3, 4, 6, 7, 8, 11], "occurr": 1, "nth_rw": 1, "consist": [1, 3, 5, 6, 7, 8], "collect": [1, 3, 5, 7], "oper": [1, 2, 3, 4, 5, 6, 7, 8], "time": [1, 4, 5, 6, 7, 8], "constant": [1, 2], "mapsto": [1, 5], "abelian": [1, 5, 6], "negat": [1, 5, 11], "invers": [1, 3, 5, 6, 8], "add_comm": [1, 4, 5, 6], "zero_add": [1, 4, 5, 6], "add_left_neg": [1, 5], "mul_on": [1, 5, 6], "one_mul": [1, 2, 5, 6], "being": [1, 3, 5, 7, 8], "suffic": [1, 2, 3, 7], "give": [1, 2, 3, 4, 6, 7], "element": [1, 2, 3, 4, 5, 6, 7, 8], "concret": [1, 2, 4, 5, 6, 7], "integ": [1, 2, 4, 6, 11], "abstract": [1, 2, 5, 6, 7], "character": [1, 3, 4, 7, 8], "axiomat": [1, 2, 3, 5], "train": [1, 6], "recogn": [1, 2, 4, 5, 6, 7], "appropri": [1, 2, 3, 5], "\u2124": [1, 4, 5, 6], "ration": [1, 2, 4, 7], "\u211a": [1, 4, 7], "\u2102": [1, 5, 8], "extend": [1, 3, 4, 5, 6, 7], "Not": [1, 5, 7], "properti": [1, 2, 3, 4, 5, 6, 7, 8], "hold": [1, 2, 3, 4, 5, 7], "arbitrari": [1, 2, 3, 4, 5], "taken": [1, 2], "cours": [1, 2, 4, 6, 7, 8], "linear": [1, 2, 5, 7], "matric": [1, 5], "fail": [1, 2, 3, 4, 5, 6, 7], "commr": [1, 2, 5], "unchang": [1, 2], "linarith": [1, 2, 4, 5], "permiss": 1, "strike": [1, 2], "balanc": 1, "concis": [1, 5], "readabl": [1, 2, 3, 4, 7], "strengthen": [1, 2, 4], "skill": [1, 2, 3, 4], "deriv": [1, 2, 4, 8], "most": [1, 2, 3, 4, 5, 6, 7], "content": [1, 4, 7], "organiz": 1, "mechan": [1, 2, 5], "namespac": [1, 2, 3, 4, 5, 7], "full": [1, 3, 4, 5, 6, 7], "shorter": [1, 3, 4, 7], "avoid": [1, 3, 4, 5, 6, 8], "due": [1, 3, 6], "clash": 1, "myre": 1, "add_right_neg": 1, "effect": [1, 3, 6, 7], "temporarili": [1, 2], "reprov": 1, "care": [1, 2, 3, 5], "earlier": 1, "pai": [1, 2, 6, 7], "attent": [1, 2, 4, 6, 7], "curli": [1, 2], "implicit": [1, 2, 5, 6, 7, 8], "moment": [1, 2, 5], "worri": [1, 3, 4, 5], "neg_add_cancel_left": 1, "add_neg_cancel_right": 1, "add_left_cancel": 1, "add_right_cancel": 1, "plan": [1, 6, 7], "brace": 1, "imagin": 1, "situat": [1, 3, 6, 7], "draw": [1, 5, 6], "conclus": [1, 2, 4], "hypothes": [1, 2, 3, 4, 5], "redund": [1, 5, 7], "few": [1, 2, 3, 4, 7], "extra": [1, 2, 3, 5, 6, 7], "oner": 1, "complic": [1, 2, 6], "tediou": [1, 2, 6], "mark": [1, 2, 6, 7], "suppos": [1, 2, 3, 4, 5, 7], "infer": [1, 2, 3, 5, 6], "mul_zero": [1, 5, 6], "serv": [1, 3, 4, 5], "therefor": [1, 4, 5, 7], "promot": 1, "modular": 1, "subproof": 1, "wa": [1, 3], "except": [1, 5], "ad": [1, 2, 3, 4, 5, 6, 7], "free": [1, 7], "At": [1, 2, 4, 5, 6], "rememb": [1, 2, 3, 4, 5, 6, 7], "zero_mul": [1, 2, 4, 5, 6], "By": [1, 3, 5, 6], "neg_eq_of_add_eq_zero": 1, "eq_neg_of_add_eq_zero": 1, "neg_zero": 1, "neg_neg": 1, "had": [1, 6], "annot": [1, 3, 4, 5, 6], "third": [1, 2, 3, 5, 7], "specifi": [1, 2, 3, 4, 5, 7, 8], "imposs": 1, "default": [1, 2, 3, 4, 5, 6, 8], "subtract": [1, 4, 5], "provabl": [1, 3, 6, 7], "sub_eq_add_neg": 1, "On": [1, 2, 3, 5, 6, 7], "defin": [1, 2, 3, 4, 6, 7, 8, 11], "reflex": [1, 2], "present": [1, 2, 4, 7], "forc": [1, 2, 3], "unfold": [1, 2, 3, 4, 5, 7], "deal": [1, 2, 3, 4, 5, 7], "equat": [1, 2, 3, 4, 5], "interchang": 1, "self_sub": 1, "either": [1, 2, 3, 5, 6, 7], "effort": [1, 4], "one_add_one_eq_two": 1, "norm_num": [1, 2, 4, 5], "strength": 1, "weaker": [1, 2], "notion": [1, 2, 3, 4, 5, 7, 8], "addgroup": 1, "otherwis": [1, 2, 3, 4, 5], "variant": [1, 2, 7], "addcommgroup": 1, "commgroup": 1, "mul_left_inv": [1, 5], "\u00b9": [1, 3, 5, 6, 7], "feel": [1, 2, 6, 7], "cocki": 1, "helper": 1, "along": [1, 4, 7], "hint": [1, 2], "mul_right_inv": [1, 5], "mul_inv_rev": 1, "non": [1, 3, 6, 7, 8], "abel": 1, "noncomm_r": 1, "seem": [1, 2, 4, 6, 7, 8], "odd": [1, 2, 3, 4], "partli": [1, 6], "histor": 1, "conveni": [1, 2, 3, 5, 6, 7], "great": [1, 5], "sort": [1, 3, 4], "inequ": [1, 2, 6, 7], "le": [1, 5, 6], "whenev": [1, 2, 4, 5], "consid": [1, 2, 3, 4, 5, 6, 7, 8], "le_refl": [1, 2], "le_tran": [1, 2], "detail": [1, 2, 3, 4, 5, 6], "unless": [1, 2, 5], "realli": [1, 2, 3, 4, 6, 7], "insist": [1, 6], "discuss": [1, 2, 4, 5, 6, 7, 8], "implic": [1, 7, 11], "h\u2080": [1, 2, 3, 4, 7], "creat": [1, 6], "option": [1, 2, 4, 5, 6, 7], "within": [1, 2, 7], "visibl": 1, "must": [1, 5, 6, 7], "complet": [1, 2, 3, 4, 6, 8], "decreas": [1, 5], "fourth": [1, 2], "mode": [1, 2, 5], "entir": [1, 3, 5, 7, 8], "lt_of_le_of_lt": [1, 2], "lt_of_lt_of_l": 1, "lt_tran": [1, 2], "togeth": [1, 2, 3, 4, 5, 7], "handl": [1, 3, 4, 6], "arithmet": 1, "5": [1, 2, 5, 7, 8], "pass": [1, 5], "exp_le_exp": 1, "mpr": [1, 2, 5, 7], "exp": [1, 3], "applic": [1, 2, 4, 5], "function": [1, 2, 4, 5, 6, 8, 11], "compound": [1, 2, 7], "pars": [1, 3], "exp_lt_exp": 1, "log_le_log": 1, "log": [1, 3], "log_lt_log": 1, "add_le_add": [1, 2], "add_le_add_left": 1, "add_le_add_right": 1, "add_lt_add_of_le_of_lt": 1, "add_lt_add_of_lt_of_l": 1, "add_lt_add_left": 1, "add_lt_add_right": 1, "add_nonneg": [1, 5], "add_po": 1, "add_pos_of_pos_of_nonneg": 1, "exp_po": [1, 3], "bi": [1, 5, 11], "lr": 1, "iff": [1, 3, 7, 8], "connect": [1, 3, 5, 7], "equival": [1, 2, 3, 4, 5, 7, 8], "mp": [1, 2, 3, 4, 7], "forward": [1, 2, 5, 7], "direct": [1, 2, 3, 6, 7, 8], "stand": [1, 2, 5, 7, 8], "modu": 1, "ponen": 1, "respect": [1, 2, 3, 4, 5, 7], "thu": [1, 3, 4, 5, 7], "again": [1, 2, 3, 4, 5, 6, 7], "numer": [1, 4, 5], "constitut": 1, "part": [1, 2, 3, 4, 5, 6, 7], "strategi": [1, 2, 4], "api": 1, "reli": [1, 2, 3, 5, 7], "guess": [1, 2, 3, 4, 5], "a_of_b_of_c": 1, "approxim": 1, "loud": 1, "probabl": [1, 5, 6, 7], "add_l": 1, "choic": [1, 2, 3, 5, 7], "exist": [1, 2, 3, 6, 7], "jump": [1, 4, 5, 7], "nearbi": [1, 4], "library_search": [1, 4], "sq_nonneg": 1, "delet": [1, 2, 3, 4], "uncom": 1, "previou": [1, 2, 3, 5, 6, 7, 8], "confirm": [1, 2, 3, 4], "finish": [1, 2, 3, 4], "job": 1, "pow_two_nonneg": [1, 2], "tend": [1, 7], "around": [1, 3, 6, 7], "binari": [1, 2, 4, 5, 6], "increas": 1, "worth": [1, 2, 5], "definition": [1, 4, 5, 7], "principl": [1, 2, 3, 4, 6, 8], "favor": [1, 2, 5], "timesav": 1, "clever": 1, "involv": [1, 2, 4, 5, 6, 7], "nice": [1, 2, 4, 6, 7], "idea": [1, 2, 3, 5, 6, 7], "abs_l": [1, 5], "ab": [1, 2, 5], "congratul": [1, 2, 4], "becom": [1, 4, 5, 6, 7], "master": [1, 4], "min": [1, 2, 7], "uniqu": [1, 2, 3, 4, 5, 7], "min_le_left": 1, "min_le_right": 1, "le_min": 1, "max": [1, 2, 6, 7], "pair": [1, 2, 4, 5, 7], "act": 1, "curri": 1, "logician": 1, "haskel": 1, "bind": [1, 3], "tighter": [1, 3], "infix": [1, 6], "le_antisymm": [1, 2], "less": [1, 2, 3, 4, 5, 6, 7], "usag": 1, "inconsist": 1, "outer": 1, "level": [1, 2, 6], "nest": [1, 2], "maintain": 1, "bother": [1, 3], "repetit": 1, "foreshadow": 1, "univers": [1, 3, 5, 7, 11], "quantifi": [1, 3, 4, 5, 7, 11], "desir": [1, 3, 6, 7], "implicitli": [1, 2], "mani": [1, 2, 3, 5, 6, 7, 8, 11], "whether": [1, 2, 3, 4, 6, 7], "Of": [1, 2, 4, 6, 7, 8], "interest": [1, 2, 3, 5, 6, 7], "vice": [1, 3], "versa": [1, 3], "word": [1, 2, 3, 4, 5, 7], "switch": [1, 6], "transit": [1, 2, 5, 7], "total": 1, "satisfi": [1, 3, 4, 5, 6, 7, 8], "disjunct": [1, 3, 11], "stick": [1, 2, 7, 8], "split": [1, 2, 3, 4], "aux": [1, 2, 4, 7], "valu": [1, 2, 3, 4, 5, 6, 7, 8], "yield": [1, 2, 3, 4, 5, 7], "made": [1, 2, 3, 5, 7], "manifest": [1, 7], "triangl": [1, 2, 5], "abs_add": [1, 2], "sub_add_cancel": [1, 5], "relat": [1, 2, 3, 5, 6, 7, 8], "ordinari": [1, 2, 4, 5, 7], "unicod": [1, 3, 6], "obtain": [1, 2, 4, 5, 7, 8], "dvd": 1, "dvd_tran": 1, "dvd_mul_of_dvd_left": 1, "dvd_mul_left": 1, "expon": 1, "expand": [1, 2, 3, 4, 5], "w": [1, 6], "greatest": [1, 5, 7], "divisor": [1, 2, 4, 5], "gcd": [1, 2, 4], "least": [1, 5, 6, 7], "lcm": 1, "analog": [1, 2, 3, 4, 7], "divid": [1, 2, 4, 5], "gcd_zero_right": 1, "gcd_zero_left": 1, "lcm_zero_right": 1, "lcm_zero_left": 1, "similarli": [1, 2, 3, 4, 5], "prefix": [1, 4, 6], "dvd_antisymm": 1, "complain": 1, "ambigu": [1, 5], "_root_": [1, 4], "saw": [1, 5, 6, 7], "govern": [1, 5], "class": [1, 4, 5, 6, 7, 8], "describ": [1, 2, 3, 4, 5, 6, 7], "\u03b1": [1, 2, 3, 4, 5, 6, 7, 8], "partialord": [1, 2], "adopt": 1, "letter": [1, 5, 8], "\u03b2": [1, 2, 3, 5, 6, 7], "\u03b3": [1, 2, 5, 7], "greek": [1, 4], "especi": [1, 5, 6, 7], "strict": [1, 2], "somewhat": [1, 3, 7], "lt_irrefl": [1, 2], "lt_iff_le_and_n": 1, "lattic": [1, 5, 6, 7], "inf_le_left": [1, 7], "inf_le_right": 1, "le_inf": 1, "le_sup_left": 1, "le_sup_right": 1, "sup_l": 1, "lower": [1, 2, 4], "bound": [1, 2, 3, 4, 5, 7, 8], "upper": [1, 2], "glb": 1, "lub": 1, "infimum": [1, 6, 7], "supremum": [1, 4, 6], "inf": [1, 6, 7], "sup": [1, 4, 7], "further": [1, 7], "matter": [1, 2], "meet": [1, 2, 3, 5], "join": [1, 5], "keep": [1, 5, 6], "dictionari": 1, "subset": [1, 2, 3, 5, 7, 8], "domain": [1, 2, 3, 4, 5, 7], "boolean": 1, "truth": [1, 4], "fals": [1, 2, 3, 4, 6], "true": [1, 2, 3, 6, 7], "posit": [1, 3, 4, 5, 7], "subspac": [1, 6], "vector": [1, 3, 6, 8], "intersect": [1, 3, 5, 6, 7], "sum": [1, 2, 4, 5, 6, 7], "inclus": [1, 3, 7], "topologi": [1, 5, 6, 8, 11], "union": [1, 3, 4, 5, 6, 8], "inf_comm": 1, "inf_assoc": 1, "sup_comm": 1, "sup_assoc": 1, "absorpt": 1, "law": 1, "absorb1": 1, "absorb2": 1, "found": [1, 5, 8], "inf_sup_self": 1, "sup_inf_self": 1, "distriblattic": 1, "inf_sup_left": 1, "inf_sup_right": 1, "sup_inf_left": 1, "sup_inf_right": 1, "shown": [1, 5, 8], "explicit": [1, 2, 5, 6, 7], "nondistribut": 1, "finit": [1, 3, 4, 5, 7, 8], "impli": [1, 2, 3, 4, 5, 7], "larger": [1, 7], "carrier": [1, 5, 6], "compat": [1, 7], "strictorderedr": 1, "mul_po": [1, 4], "mul_nonneg": 1, "coupl": [1, 2, 6, 7], "metric": [1, 5, 8, 11], "equip": [1, 3, 5, 6, 7, 8], "distanc": [1, 2, 7, 8], "dist": [1, 7], "map": [1, 2, 3, 5, 6, 7], "metricspac": [1, 7, 8], "dist_self": 1, "dist_comm": [1, 7], "dist_triangl": [1, 7], "nonneg": [1, 5], "nonneg_of_mul_nonneg_left": 1, "dist_nonneg": [1, 7], "dealt": 2, "basic": [2, 4, 5, 7, 11], "simpl": [2, 4, 5, 6, 8], "absolut": 2, "\u03b5": [2, 7, 8], "though": [2, 3, 4, 5], "treat": [2, 3, 5, 6, 7, 8], "my_lemma": 2, "\u03b4": [2, 7], "hb": [2, 7], "subsequ": [2, 4, 7], "lemma": [2, 4, 5, 6, 7, 8, 11], "mention": [2, 3, 5, 6, 7], "my_lemma2": 2, "stage": [2, 5, 6], "my_lemma3": 2, "epo": 2, "ele1": 2, "xlt": 2, "ylt": 2, "essenti": [2, 3, 5, 7], "colon": 2, "why": [2, 4, 6, 7], "off": [2, 3, 4], "my_lemma4": 2, "abs_mul": 2, "mul_le_mul": 2, "abs_nonneg": 2, "mul_lt_mul_right": 2, "extract": [2, 7], "hidden": 2, "expos": [2, 7], "predic": [2, 3, 4, 6, 7, 8], "fnub": 2, "fnlb": 2, "hfa": 2, "hgb": 2, "dsimp": [2, 3, 4, 5], "simplif": [2, 3, 4], "contract": 2, "anyhow": 2, "control": 2, "transform": [2, 3], "rest": [2, 3, 5, 7], "routin": 2, "nnf": 2, "nng": 2, "hfb": 2, "nna": 2, "order": [2, 3, 4, 5, 6, 7, 8, 11], "codomain": [2, 4, 7], "structur": [2, 4, 6, 7, 8, 11], "monoid": [2, 3, 4, 6], "fnub_add": 2, "orderedcanceladdcommmonoid": 2, "high": 2, "monoton": [2, 6, 7], "nondecreas": [2, 4], "placehold": 2, "Or": [2, 3], "backward": [2, 7], "subgoal": 2, "mf": 2, "mg": 2, "aleb": 2, "lambda": [2, 5], "flag": [2, 3], "squiggli": 2, "marker": 2, "nnc": 2, "bbb": [2, 5], "fneven": 2, "fnodd": 2, "ef": 2, "eg": 2, "og": 2, "shorten": 2, "rid": 2, "won": [2, 4, 6, 7], "cannot": [2, 3, 4, 5, 6, 7], "contrari": 2, "syntact": 2, "reduct": [2, 3], "erw": 2, "harder": 2, "spot": 2, "rudimentari": 2, "foundat": [2, 3, 4, 5], "impos": 2, "restrict": [2, 3, 4, 7], "talk": [2, 4, 7, 8], "assert": [2, 3, 6], "ask": [2, 4, 5, 6, 7], "refl": [2, 3, 5, 6], "tran": [2, 4, 5, 6], "setub": 2, "inject": [2, 3, 4, 6, 7], "x_1": [2, 3], "x_2": [2, 3], "x\u2081": [2, 3, 5, 7], "x\u2082": [2, 3, 5], "add": [2, 4, 5, 6, 7, 8], "nonzero": [2, 4, 5], "add_left_inj": 2, "composit": [2, 3, 5, 6, 7], "injg": 2, "injf": [2, 3], "canon": [2, 3, 4, 5], "exhibit": [2, 7], "anonym": [2, 3, 4, 5], "constructor": [2, 3, 4, 5, 6], "angl": 2, "whatev": [2, 4], "certain": [2, 6, 7], "fnhasub": 2, "fnhaslb": 2, "ubf": 2, "ubg": 2, "ubfa": 2, "ubgb": 2, "unpack": [2, 3], "claus": [2, 6], "whose": [2, 4, 5, 6, 7, 8], "els": [2, 3, 4], "turn": [2, 3, 4, 5, 6, 7, 8], "fn_ub_add": 2, "directli": [2, 4, 5, 6, 7], "lbf": 2, "lbg": 2, "cousin": 2, "rcase": [2, 3, 4, 5, 7], "flexibl": [2, 7], "recurs": [2, 3, 5, 11], "harm": [2, 3], "swiss": 2, "armi": 2, "knive": 2, "wide": 2, "old": [2, 5, 6], "chestnut": 2, "product": [2, 4, 5, 6, 7], "magic": [2, 5, 6], "verifi": 2, "sumofsquar": 2, "sumofsquares_mul": 2, "sosx": 2, "sosi": 2, "xeq": [2, 3], "yeq": 2, "insight": 2, "motiv": 2, "gaussian": [2, 11], "sqrt": [2, 3, 4, 5], "norm": [2, 5, 7, 11], "reflect": 2, "di": [2, 5], "xy": [2, 5], "cryptic": 2, "easiest": [2, 4], "perspicu": 2, "divis": [2, 4, 5, 6, 11], "divab": 2, "divbc": 2, "beq": 2, "ceq": 2, "And": [2, 4, 6, 7], "pretti": [2, 6, 7], "Then": [2, 3, 5, 6, 7], "divac": 2, "alpha": [2, 3], "beta": [2, 3], "surject": [2, 3, 7], "yourself": [2, 5], "field_simp": [2, 5], "denomin": [2, 4, 5], "div_mul_cancel": 2, "hx": [2, 3, 5, 6, 8], "method": [2, 3, 4, 5], "surjg": 2, "surjf": [2, 3], "strictli": [2, 8], "contradict": [2, 3, 4], "speak": [2, 5, 7], "irreflex": 2, "asymmetri": 2, "lt_asymm": 2, "sugar": 2, "eventu": [2, 3, 7], "fnuba": 2, "not_le_of_gt": 2, "not_lt_of_g": [2, 4, 5], "lt_of_not_g": 2, "le_of_not_gt": 2, "snippet": [2, 4, 5], "counterexampl": [2, 8], "monof": 2, "four": [2, 5], "valid": 2, "far": [2, 3, 6, 7], "q": [2, 4, 5, 6, 7], "straightforward": [2, 6], "difficult": [2, 6], "conclud": [2, 8], "nonexist": 2, "contradictori": 2, "classic": [2, 3, 4], "by_contra": [2, 4], "not_not": 2, "front": 2, "push": [2, 4, 7], "inward": 2, "facilit": [2, 7], "push_neg": [2, 3, 4], "restat": [2, 6], "contrapos": [2, 3, 4], "yet": [2, 3, 4, 5, 6, 7], "semicolon": [2, 4], "falso": 2, "anyth": [2, 5, 7], "elim": 2, "strang": [2, 4], "fairli": 2, "reach": [2, 6], "37": 2, "exfalso": 2, "absurd": [2, 4], "slick": 2, "drop": 2, "manner": [2, 5], "contrast": [2, 3, 5, 7], "compon": [2, 3, 5, 7], "techniqu": [2, 7], "variou": [2, 3, 5, 6], "xltz": 2, "zlty": 2, "10": 2, "7": [2, 4], "behav": [2, 3, 6, 7], "roughli": [2, 3, 4], "friend": [2, 5], "were": [2, 4, 5, 7], "inscrut": [2, 3], "gadget": [2, 7], "suggest": [2, 4, 5, 7], "auxiliari": [2, 7], "pow_eq_zero": [2, 4], "doubl": [2, 3], "symmetr": [2, 3], "abs_lt": 2, "dvd_gcd_iff": 2, "8": [2, 4, 7], "6": [2, 4, 5, 6, 7, 8], "15": 2, "below": [2, 3, 4, 5, 6, 7, 8], "not_monotone_iff": 2, "antisymmetr": 2, "aris": 2, "preorder": [2, 6, 7], "pre": 2, "lt_iff_le_not_l": 2, "beyond": [2, 6, 8], "repeatedli": [2, 7], "instanti": [2, 5, 6, 7], "inl": [2, 3], "inr": [2, 3], "produc": [2, 8], "branch": [2, 3, 6], "le_or_gt": 2, "abs_of_nonneg": [2, 5], "abs_of_neg": 2, "immedi": [2, 3, 5, 6], "myab": 2, "le_abs_self": 2, "neg_le_abs_self": 2, "enjoi": [2, 3, 4, 7], "pun": 2, "lt_ab": 2, "genuin": 2, "vertic": [2, 5], "lt_trichotomi": 2, "xgt": 2, "dvd_mul_right": [2, 4], "eq_zero_or_eq_zero_of_mul_eq_zero": 2, "zero": [2, 3, 4, 5, 6, 7, 8], "nontrivi": [2, 3, 4, 5, 7], "integr": [2, 8], "isdomain": 2, "em": [2, 3], "exclud": [2, 4], "by_cas": [2, 3, 4], "dispos": 2, "s_0": [2, 3], "s_1": 2, "s_2": 2, "ldot": [2, 3, 4], "varepsilon": [2, 7], "s_n": [2, 3], "render": [2, 4], "convergesto": 2, "ext": [2, 3, 4, 5, 6], "enabl": [2, 3, 4, 5], "actual": [2, 3, 4, 6, 7], "congr": 2, "reconcil": 2, "peel": 2, "convert": [2, 4], "quit": [2, 6, 7], "zero_lt_on": [2, 4], "fill": [2, 3, 4, 5], "convergesto_const": 2, "\u03b5po": [2, 7], "nge": 2, "abs_zero": 2, "save": [2, 3], "troubl": [2, 3, 5], "pen": 2, "paper": [2, 3, 5, 7], "nt": 2, "maximum": [2, 4, 7], "implement": [2, 5, 6, 8], "convergesto_add": 2, "ct": 2, "\u03b52po": 2, "ht": 2, "le_of_max_le_left": 2, "le_of_max_le_right": 2, "tricki": [2, 3, 4, 6], "convergesto_mul_const": 2, "mulzeroclass": [2, 6], "acpo": 2, "abs_po": 2, "independ": [2, 3, 5], "exists_abs_le_of_convergesto": 2, "strong": [2, 4], "n\u2080": 2, "bpo": [2, 7], "pos\u2080": 2, "div_po": 2, "n\u2081": 2, "convergesto_mul": 2, "sketch": [2, 3, 4, 7], "limit": [2, 6, 7], "bold": 2, "scratch": 2, "convergesto_uniqu": 2, "sa": 2, "sb": 2, "abn": 2, "na": 2, "hna": 2, "nb": 2, "hnb": 2, "absa": 2, "absb": 2, "observ": [2, 4, 7], "everywher": [2, 3, 6, 7], "linearord": 2, "vastli": 2, "awai": [2, 5], "vocabulari": 3, "uniform": [3, 7, 8], "primit": 3, "conceptu": 3, "advantag": [3, 4, 5, 8], "overload": 3, "verbos": 3, "system": [3, 4, 5, 6], "wrong": 3, "theoret": [3, 7], "ss": 3, "sub": [3, 7, 11], "cap": 3, "un": 3, "cup": 3, "univ": [3, 7, 8], "empti": [3, 4, 5, 7], "member": [3, 7], "membership": [3, 4, 6], "mem": 3, "notin": 3, "ident": [3, 4, 5, 6, 7, 11], "databas": [3, 4, 6, 7], "unlik": [3, 4], "existenti": [3, 11], "subset_def": 3, "inter_def": 3, "xu": 3, "mem_inter_iff": 3, "xsu": 3, "phenomenon": 3, "quirk": 3, "process": 3, "pitfal": 3, "heavili": [3, 7], "fall": 3, "union_def": 3, "mem_union": [3, 4], "xtu": 3, "xt": 3, "unnecessari": 3, "clearer": [3, 5], "correctli": 3, "special": [3, 4, 5, 6, 7], "rewritten": 3, "diff_eq": 3, "mem_diff": 3, "xstu": 3, "xnt": 3, "xnu": 3, "extension": [3, 5], "unsurprisingli": 3, "dollar": 3, "sign": [3, 7], "and_comm": 3, "antisymm": 3, "hood": [3, 5], "builder": 3, "trivial": [3, 4, 7], "eq_two_or_odd": 3, "even_iff": 3, "confus": [3, 4, 6, 7], "fortun": 3, "agre": 3, "prime_iff": 3, "symm": [3, 4, 5, 6, 7, 8], "rwa": [3, 4, 5], "signific": 3, "ball": [3, 8], "bex": 3, "bex_def": 3, "prime_x": 3, "slight": 3, "ssubt": 3, "index": [3, 6, 7], "model": [3, 7], "sequenc": [3, 6, 7, 8, 11], "a_0": 3, "a_1": 3, "a_2": 3, "mem_iunion": 3, "xai": 3, "mem_iint": 3, "mem_union\u2082": 3, "mem_inter\u2082": 3, "mem_iunion\u2082": 3, "exists_prime_and_dvd": 3, "eq_univ": 3, "eq_univ_of_foral": 3, "exists_infinite_prim": 3, "\u2080": 3, "sunion": 3, "sinter": 3, "relationship": [3, 4], "mem_iinter\u2082": 3, "sunion_eq_biunion": 3, "sinter_eq_biint": 3, "preimag": [3, 7], "imag": [3, 4, 6, 7], "tripl": 3, "tag": [3, 6], "mem_image_of_mem": 3, "galoi": [3, 5, 7], "image_subset_iff": 3, "represent": [3, 4, 5], "asid": 3, "raini": 3, "dai": 3, "behavior": [3, 6, 7], "nonempti": [3, 7], "condit": [3, 4, 6, 7, 8], "fxeq": 3, "ai": 3, "fx": 3, "eq": [3, 5], "injon": 3, "theme": 3, "rel": [3, 5], "relativ": 3, "xpo": 3, "ypo": 3, "exp_log": 3, "ingredi": [3, 5, 7, 8], "assign": [3, 5, 6], "inhabit": [3, 5, 7], "appeal": [3, 6], "choose_spec": 3, "some_spec": 3, "noncomput": [3, 5], "inverse_spec": 3, "dif_po": 3, "dif_neg": 3, "fulli": [3, 7], "alon": 3, "leftinvers": 3, "rightinvers": 3, "hack": 3, "half": 3, "dozen": 3, "condens": 3, "cantor": 3, "famou": 3, "miss": [3, 4], "j": [3, 5], "intuit": [3, 7], "cardin": 3, "biject": [3, 5], "nineteenth": 3, "centuri": 3, "infinit": [3, 7, 11], "dedekind": 3, "quickli": 3, "behind": 3, "problem": [3, 4, 5, 6, 7], "shade": 3, "region": 3, "diagram": 3, "circ": [3, 5], "scale": 3, "inner": 3, "smaller": [3, 4, 7], "concentr": 3, "unshad": 3, "compos": [3, 5, 7], "disjoint": 3, "sound": [3, 5, 6], "plausibl": 3, "delic": 3, "improv": [3, 4], "confid": 3, "better": [3, 4, 5, 6, 7], "invfun": [3, 5], "leftinverse_invfun": 3, "invfun_eq": 3, "sbaux": 3, "sbset": 3, "sb_aux": 3, "s_": 3, "sb_set": 3, "bigcup_": 3, "mathbb": [3, 4, 5], "sbfun": 3, "complement": [3, 7], "outermost": 3, "setminu": 3, "inv_fun": 3, "inv_fun_eq": 3, "sb_right_inv": 3, "goe": [3, 4, 5, 6, 7], "henc": [3, 4, 5, 6, 7, 8], "neither": [3, 5, 6], "nor": [3, 5], "sb_inject": 3, "hf": [3, 7, 8], "hg": [3, 7, 8], "a_def": 3, "h_def": 3, "hxeq": 3, "xa": [3, 5], "wlog": 3, "x\u2081a": 3, "resolve_left": 3, "x\u2082a": 3, "not_imp_self": 3, "x\u2082na": 3, "if_po": 3, "if_neg": 3, "x\u2082eq": 3, "hn": [3, 4, 7, 8], "sb_fun": 3, "bring": [3, 4, 7], "tradeoff": 3, "encapsul": [3, 5, 8], "symmetri": [3, 6], "dwell": 3, "succ": [3, 4, 6], "sb_surject": 3, "gya": 3, "xmem": 3, "sweet": 3, "schroeder_bernstein": 3, "substant": 4, "ancient": 4, "fraction": 4, "lowest": 4, "2c": 4, "4c": 4, "factor": [4, 5], "coprim": 4, "smart": 4, "12": 4, "encount": [4, 6], "algebra": [4, 6, 7, 8, 11], "prime_def_lt": 4, "eq_one_or_self_of_dvd": 4, "prime_p": 4, "17": 4, "commonli": [4, 5], "prime_two": 4, "prime_thre": 4, "broader": [4, 8], "irreduc": [4, 5], "coincid": [4, 5, 7], "rise": [4, 6], "dvd_mul": 4, "even_of_even_sqr": 4, "dvd_of_dvd_pow": 4, "proce": [4, 6], "profici": 4, "search": [4, 5, 6], "engin": 4, "hesit": 4, "mul_right_inj": 4, "heart": 4, "irration": 4, "dvd_gcd": 4, "coprime_mn": 4, "sqr_eq": 4, "meq": 4, "dvd_iff_exists_eq_mul_left": 4, "two_l": 4, "le_of_dvd": 4, "approach": [4, 5, 6, 7], "quick": [4, 8], "ne": [4, 5], "occur": 4, "suffici": [4, 7], "permut": 4, "prime_of_mem_factor": 4, "prod_factor": 4, "factors_uniqu": 4, "factorization_mul": 4, "mnez": 4, "nnez": 4, "factorization_pow": 4, "black": [4, 6], "box": 4, "simpa": [4, 8], "nnz": 4, "nsqr_nez": 4, "eq1": 4, "eq2": 4, "add_mul_mod_self_left": 4, "mul_mod_right": 4, "count_factors_mul_of_po": 4, "successor": 4, "succ_ne_zero": 4, "npow_nz": 4, "dvd_sub": 4, "pow_eq": 4, "npowz": 4, "add_sub_cancel": 4, "understood": [4, 7], "quotient": [4, 5, 6, 7], "pictur": [4, 5], "mediat": 4, "headach": 4, "contend": 4, "issu": [4, 5, 6, 7], "th": 4, "topic": [4, 6], "enat": 4, "infin": [4, 7], "appreci": 4, "role": [4, 5, 7], "writ": 4, "datatyp": 4, "freeli": 4, "translat": [4, 6, 7], "mathematician": [4, 7], "inj": 4, "factori": 4, "fac": 4, "ih": 4, "fac_po": 4, "succ_po": 4, "dvd_fac": 4, "ipo": 4, "il": 4, "of_le_succ": 4, "dvd_mul_of_dvd_right": 4, "crude": 4, "remaind": [4, 5], "pow_two_le_fac": 4, "finset": [4, 5, 7], "bigoper": [4, 5], "prod": [4, 7], "sum_range_zero": 4, "sum_range_succ": 4, "summat": 4, "prod_range_zero": 4, "prod_range_succ": 4, "deserv": 4, "comment": 4, "danger": [4, 5], "ordinarili": [4, 5], "loop": 4, "indefinit": 4, "fix": [4, 6, 7], "placement": 4, "re": [4, 5], "handi": 4, "sum_id": 4, "div_eq_of_eq_mul_right": 4, "succ_eq_add_on": 4, "sum_sqr": 4, "mynat": 4, "thumb": 4, "decid": [4, 7], "preced": 4, "truncat": 4, "exponenti": 4, "cut": 4, "predecessor": 4, "pred": 4, "mul": [4, 5, 6, 7], "succ_add": 4, "succ_mul": 4, "explor": [4, 7], "standard": [4, 5, 6, 7], "formul": [4, 7], "quirki": 4, "among": 4, "annoi": [4, 6], "h0": 4, "succ_le_succ": 4, "zero_l": [4, 5], "interval_cas": 4, "interv": [4, 7], "decis": 4, "procedur": [4, 6], "revert": [4, 5], "minfac": 4, "smallest": [4, 6, 7], "strong_induction_on": 4, "subsum": 4, "exists_prime_factor": 4, "np": 4, "mltn": 4, "mdvdn": 4, "mne1": 4, "mz": 4, "zero_dvd_iff": 4, "mgt2": 4, "pp": 4, "pdvd": 4, "factorial_po": 4, "dvd_factori": 4, "primes_infinit": 4, "refin": [4, 8], "ple": 4, "p_1": 4, "p_n": 4, "prod_": 4, "p_i": [4, 7], "computation": 4, "test": 4, "decidableeq": 4, "abandon": 4, "ourselv": [4, 6], "subset_iff": 4, "mem_int": 4, "mem_sdiff": 4, "tauto": 4, "dispens": 4, "tautologi": 4, "dvd_prod_of_mem": 4, "eq_of_dvd_of_prim": 4, "prime_q": 4, "preserv": [4, 6, 7], "induction_on": 4, "singleton": 4, "prod_empti": 4, "prod_insert": 4, "mem_of_dvd_prod_prim": 4, "mem_insert": 4, "wrote": 4, "filter": [4, 8, 11], "mem_filt": 4, "aim": 4, "prod_po": 4, "_def": 4, "mem_": 4, "id": [4, 6, 7, 8], "bounded_of_ex_finset": 4, "qk": 4, "lt_succ_of_l": 4, "le_sup": 4, "ex_finset_of_bound": 4, "decidablepr": 4, "lt_succ_iff": 4, "congruent": 4, "p_k": 4, "loss": 4, "27": 4, "mod_4_eq_3_or_mod_4_eq_3": 4, "mul_mod": 4, "mod_lt": 4, "hm": [4, 8], "two_le_of_mod_4_eq_3": 4, "neq": 4, "div_dvd_of_dvd": 4, "div_lt_self": 4, "piec": [4, 5, 6, 7], "exists_prime_factor_mod_4_eq_3": 4, "dvd_rfl": 4, "mge2": 4, "mul_div_cancel": 4, "home": [4, 5], "stretch": [4, 5], "remov": [4, 7], "eras": 4, "mem_eras": 4, "readi": [4, 6, 7, 8], "dvd_add_iff_left": 4, "primes_mod_4_eq_3_infinit": 4, "p4": 4, "pltn": 4, "p4eq": 4, "pne3": 4, "seriou": [4, 6, 7], "feat": 4, "modern": 5, "subject": 5, "mysteri": [5, 6], "technic": [5, 6], "consult": 5, "ann": 5, "baanen": 5, "abus": 5, "paramet": [5, 6], "broadest": 5, "possibli": 5, "constraint": [5, 7], "bundl": [5, 6, 7, 8], "tupl": 5, "hy": [5, 6], "hz": [5, 6], "mypoint1": 5, "mypoint2": 5, "mypoint3": 5, "mk": [5, 6, 7], "former": 5, "latter": [5, 7], "quot": [5, 7], "protect": 5, "intern": 5, "add_x": 5, "addalt": 5, "etc": [5, 7], "y\u2081": 5, "z\u2081": 5, "y\u2082": 5, "z\u2082": 5, "addalt_x": 5, "addalt_comm": 5, "ya": 5, "za": 5, "xb": 5, "yb": 5, "zb": 5, "apart": 5, "effici": [5, 7], "scalar": [5, 6, 8], "smul": [5, 6], "smul_distrib": 5, "road": 5, "link": [5, 6], "belong": [5, 6, 7], "simplex": 5, "convinc": 5, "equilater": 5, "interior": [5, 8], "standardtwosimplex": 5, "x_nonneg": 5, "y_nonneg": 5, "z_nonneg": 5, "sum_eq": 5, "swap": 5, "swapxi": 5, "interestingli": [5, 8], "midpoint": 5, "div_nonneg": 5, "weight": 5, "averag": 5, "analogi": [5, 7, 8], "weightedaverag": 5, "lambda_nonneg": 5, "lambda_l": 5, "fin": 5, "standardsimplex": 5, "sum_eq_on": 5, "div_eq_mul_inv": 5, "sum_mul": 5, "sum_add_distrib": 5, "mul_sum": 5, "manipul": [5, 7], "islinear": 5, "is_addit": 5, "preserves_mul": 5, "linf": 5, "subtyp": [5, 6, 7], "preal": 5, "val": 5, "sigma": 5, "wherebi": [5, 7], "stdsimplex": 5, "\u03c3": 5, "fst": [5, 7], "snd": [5, 7], "custom": 5, "robust": [5, 6], "interfac": 5, "redefin": [5, 6], "accessor": 5, "weav": 5, "rich": [5, 6], "interconnect": 5, "hierarchi": [5, 11], "clarifi": 5, "antireflex": 5, "cdot": 5, "topolog": [5, 6, 8, 11], "mathcal": [5, 8], "proxi": 5, "bipartit": 5, "graph": 5, "categori": [5, 7, 8], "morphism": [5, 8, 11], "basi": [5, 7], "discret": [5, 8], "inherit": [5, 6], "polynomi": 5, "coeffici": 5, "dual": [5, 7], "accommod": 5, "almost": [5, 6, 7], "marriag": 5, "heaven": 5, "group\u2081": [5, 6], "inv": [5, 6], "struc": 5, "counterpart": 5, "chosen": 5, "assur": 5, "groupcat": 5, "group\u2081cat": 5, "str": 5, "capit": 5, "roman": 5, "equiv": 5, "tofun": [5, 6], "right_inv": 5, "left_inv": 5, "creativ": 5, "evid": 5, "coercion": [5, 6, 7, 8], "omit": 5, "perm": 5, "under": [5, 6, 7], "orient": 5, "permgroup": 5, "trans_assoc": 5, "trans_refl": 5, "refl_tran": 5, "self_trans_symm": 5, "grouptheori": 5, "g_1": 5, "g_2": 5, "g_3": 5, "tightli": 5, "isomorph": [5, 8], "additivegroup": 5, "Its": [5, 6], "neg": [5, 6, 7], "reproduc": 5, "accompani": 5, "addgroup\u2081": 5, "scheme": 5, "addgrouppoint": 5, "arrang": 5, "mul_inv_cancel_right": 5, "achiev": [5, 6, 7], "silent": [5, 6], "regist": [5, 6], "grp": 5, "contextu": 5, "cue": 5, "synthes": [5, 6], "whole": 5, "_inst_1": 5, "candid": 5, "group\u2082": 5, "mysquar": 5, "my_squar": 5, "remark": [5, 6], "head": 5, "store": 5, "headi": 5, "hasmulgroup\u2082": 5, "hasonegroup\u2082": 5, "hasinvgroup\u2082": 5, "suppli": 5, "accord": 5, "capabl": 5, "chain": 5, "recent": 5, "prioriti": 5, "bad": [5, 6, 7], "artifici": 5, "addgroup\u2082": 5, "subtl": [5, 7], "configur": 5, "invisibli": [5, 6], "wise": 5, "euclidean": 5, "terminologi": 5, "mid": 5, "imaginari": 5, "gaussint": 5, "im": 5, "pointwis": [5, 7, 8], "root": [5, 6, 11], "ac": 5, "bci": 5, "adi": 5, "bd": 5, "bc": 5, "hasmul": 5, "zero_def": 5, "one_def": 5, "add_def": 5, "neg_def": 5, "mul_def": 5, "zero_r": 5, "zero_im": 5, "one_r": 5, "one_im": 5, "add_r": 5, "add_im": 5, "neg_r": 5, "neg_im": 5, "mul_r": 5, "mul_im": 5, "surprisingli": [5, 6], "concept": [5, 7, 8], "light": 5, "bulb": 5, "skeleton": [5, 7], "scari": 5, "entri": 5, "instcommr": 5, "left_distrib": [5, 6], "right_distrib": [5, 6], "ext_iff": 5, "bq": 5, "archetyp": 5, "int": [5, 6], "ediv_add_emod": 5, "emod_nonneg": 5, "emod_lt": 5, "unit": [5, 6, 7], "algorithm": 5, "conjug": 5, "frac": 5, "nearest": 5, "size": 5, "vi": 5, "multipli": 5, "view": [5, 6, 7], "emb": 5, "forth": 5, "quadrat": 5, "gaussian_int": 5, "stai": 5, "face": [5, 6, 7], "machineri": [5, 6, 7], "adapt": 5, "invest": 5, "pragmat": 5, "seek": 5, "heather": 5, "macbeth": 5, "eleg": 5, "div": 5, "mod": 5, "_add_mod": 5, "abs_mod": 5, "_le": 5, "emod_lt_of_po": 5, "zero_lt_two": 5, "fixm": 5, "_eq": 5, "sq_add_sq_eq_zero": 5, "linearorderedr": 5, "norm_nonneg": [5, 8], "norm_eq_zero": [5, 8], "norm_po": 5, "norm_mul": [5, 8], "conj": 5, "conj_r": 5, "conj_im": 5, "norm_conj": 5, "bespok": 5, "quad": 5, "record": [5, 6], "div_def": 5, "mod_def": 5, "messi": 5, "nicer": [5, 7], "norm_mod_lt": 5, "norm_y_po": 5, "sq_ab": 5, "gcongr": 5, "ediv_mul_l": 5, "le_of_mul_le_mul_right": 5, "ediv_lt_of_lt_mul": 5, "natab": 5, "coe_natabs_norm": 5, "natabs_of_nonneg": 5, "natabs_norm_mod_lt": 5, "ofnat_lt": 5, "coe_natab": 5, "not_norm_mul_left_lt_norm": 5, "natabs_mul": 5, "le_mul_of_one_le_right": 5, "ofnat_l": 5, "add_one_le_of_lt": 5, "euclideandomain": 5, "quotient_mul_add_remainder_eq": 5, "quotient_zero": 5, "r_wellfound": 5, "remainder_lt": 5, "mul_left_not_lt": 5, "payoff": 5, "principalidealr": 5, "irreducible_iff_prim": 5, "studi": [6, 7], "prematur": 6, "technologi": 6, "simpler": 6, "ring\u2081": 6, "gradual": [6, 7], "bottom": [6, 7], "endow": 6, "one\u2081": 6, "heavier": 6, "inferr": 6, "resolut": 6, "ie": [6, 7], "attribut": 6, "ensur": [6, 7], "self": 6, "one\u2082": 6, "usabl": 6, "silli": 6, "affect": 6, "importantli": 6, "habit": 6, "ascript": 6, "messag": 6, "typeclass": 6, "stuck": 6, "metavari": 6, "263": 6, "auto": 6, "sever": [6, 7], "unknown": 6, "collis": 6, "builtin": 6, "\ud835\udfd9": 6, "inherit_doc": 6, "diamond": 6, "dia\u2081": 6, "dia": 6, "infixl": 6, "70": 6, "semigroup": 6, "dia_assoc": 6, "semigroup\u2081": 6, "todia\u2081": 6, "previous": 6, "semigroup\u2082": 6, "hurdl": 6, "neutral": 6, "diaoneclass\u2081": 6, "one_dia": 6, "dia_on": 6, "trace": 6, "info": 6, "ters": 6, "expend": 6, "attempt": 6, "succce": 6, "success": 6, "set_opt": 6, "meta": 6, "synthinst": 6, "monoid\u2081": 6, "hide": [6, 7], "subtleti": 6, "fear": 6, "unrel": 6, "tosemigroup\u2081": 6, "todiaoneclass\u2081": 6, "monoid\u2082": 6, "defect": [6, 7], "toone\u2081": 6, "overlap": 6, "tear": 6, "appart": 6, "signatur": 6, "restor": 6, "optim": 6, "reusabl": 6, "inv\u2081": 6, "postfix": 6, "inv_dia": 6, "weak": 6, "preliminari": 6, "left_inv_eq_right_inv\u2081": 6, "hba": 6, "hac": 6, "export": 6, "inv_eq_of_dia": 6, "dia_inv": 6, "naiv": [6, 7], "duplic": 6, "attibut": 6, "to_addit": 6, "semi": 6, "left_inv_eq_right_inv": 6, "left_neg_eq_right_neg": 6, "whatsnew": 6, "addsemigroup\u2083": 6, "add_assoc\u2083": 6, "semigroup\u2083": 6, "mul_assoc\u2083": 6, "addmonoid\u2083": 6, "addzeroclass": 6, "monoid\u2083": 6, "muloneclass": 6, "tomuloneclass": 6, "addcommsemigroup\u2083": 6, "commsemigroup\u2083": 6, "addcommmonoid\u2083": 6, "commmonoid\u2083": 6, "addgroup\u2083": 6, "neg_add": 6, "group\u2083": 6, "inv_mul": 6, "approri": 6, "inv_eq_of_mul": 6, "propag": 6, "attr": 6, "mul_inv": 6, "mul_left_cancel\u2083": 6, "mul_right_cancel\u2083": 6, "addcommgroup\u2083": 6, "commgroup\u2083": 6, "demonstr": [6, 7], "puprpos": 6, "opposit": [6, 7], "gain": 6, "besid": 6, "parent": 6, "ring\u2083": 6, "toaddgroup\u2083": 6, "mayb": 6, "le\u2081": 6, "50": 6, "\u2081": 6, "preorder\u2081": 6, "partialorder\u2081": 6, "orderedcommmonoid\u2081": 6, "modul": 6, "pretend": 6, "smul\u2083": 6, "infixr": 6, "73": 6, "module\u2081": 6, "zero_smul": 6, "one_smul": 6, "mul_smul": 6, "add_smul": 6, "smul_add": 6, "surpris": 6, "addcommgroup3": 6, "toaddcommgroup\u2083": 6, "inst": 6, "module\u2083": 6, "hunt": 6, "unspecifi": 6, "embark": 6, "main": [6, 7, 8], "quest": 6, "huge": 6, "trap": 6, "refus": [6, 7], "tosmul\u2083": 6, "inst_1": 6, "safe": 6, "selfmodul": 6, "invert": 6, "nsmul\u2081": 6, "zsmul\u2081": 6, "ofnat": 6, "negsucc": 6, "intermedi": [6, 7], "abgrpmodul": 6, "frustat": 6, "failur": 6, "synth": 6, "indirect": 6, "path": 6, "thank": [6, 7], "definitionnali": 6, "offend": 6, "poor": 6, "forget": 6, "http": 6, "inria": 6, "hal": 6, "scienc": 6, "02463336": 6, "modifi": 6, "nsmul": 6, "addmonoid\u2084": 6, "nsmul_zero": 6, "nsmul_succ": 6, "mysmul": 6, "stori": 6, "incorpor": 6, "zsmul": 6, "incorport": 6, "lt\u2081": 6, "comparison": 6, "ismonoidhom\u2081": 6, "unpleas": [6, 7], "conjunct": [6, 11], "chose": 6, "ismonoidhom\u2082": 6, "map_on": 6, "map_mul": 6, "tempt": 6, "higher": 6, "unif": 6, "psycholog": 6, "rare": 6, "adject": 6, "bare": 6, "noun": 6, "argu": 6, "continuous_id": [6, 7], "primari": 6, "constrast": 6, "monoidhom\u2081": 6, "coefun": 6, "coerc": 6, "coe": 6, "addmonoidhom\u2081": 6, "addmonoid": 6, "map_zero": 6, "map_add": [6, 8], "ringhom\u2081": 6, "minor": [6, 8], "tomonoidhom\u2081": 6, "juggl": 6, "monoidhomclass\u2081": 6, "badinst": 6, "wouldn": 6, "priori": 6, "slightli": [6, 7, 8], "boil": 6, "hopelessli": 6, "checksynthord": 6, "random": 6, "deduc": [6, 7], "outparam": 6, "trigger": 6, "retri": 6, "monoidhomclass\u2082": 6, "promis": [6, 7], "morphim": 6, "map_inv_of_inv": 6, "sight": 6, "got": 6, "presenc": 6, "repeatit": 6, "layer": [6, 7], "funlik": 6, "monoidhomclass": 6, "monoidhomclass\u2083": 6, "coe_inject": 6, "stop": 6, "ringhomclass\u2083": 6, "ringhom": 6, "algebrahom": 6, "ve": [6, 7], "primarili": [6, 7], "unbundl": 6, "orderpreshom": 6, "le_of_l": 6, "orderpresmonoidhom": 6, "orderpreshomclass": 6, "subgroup": 6, "subr": 6, "reus": 6, "led": 6, "descend": 6, "break": 6, "barrier": 6, "setlik": 6, "wrap": [6, 7], "submonoid\u2081": 6, "submonoid": 6, "mul_mem": 6, "one_mem": 6, "tackl": 6, "setco": 6, "submonoid\u2081monoid": 6, "destructur": 6, "binder": 6, "submonoidclass\u2081": 6, "subgroup\u2081": 6, "subgroupclass\u2081": 6, "subobject": 6, "s\u2081": 6, "s\u2082": 6, "shame": 6, "across": 6, "weird": [6, 7], "distract": 6, "emphas": 6, "anecdot": 6, "devic": 6, "hasquoti": 6, "bewar": 6, "regular": [6, 7], "ascii": 6, "setoid": 6, "commmonoid": 6, "iseqv": 6, "hw": 6, "quotientmonoid": 6, "map\u2082": 6, "calculu": [7, 11], "quantiti": 7, "begun": 7, "paradox": 7, "exot": 7, "x\u2080": [7, 8], "convention": 7, "eight": 7, "varieti": 7, "wish": 7, "64": 7, "y\u2080": 7, "z\u2080": 7, "paragraph": 7, "512": 7, "bourbaki": 7, "spell": 7, "dualli": 7, "arbitrarili": 7, "neighborhood": 7, "at_top": 7, "\ud835\udcdd": [7, 8], "\ud835\udce4": 7, "entourag": 7, "\u03bc": 7, "a_": 7, "univ_set": 7, "sets_of_superset": 7, "inter_set": 7, "blur": 7, "princip": 7, "\ud835\udcdf": 7, "opportun": 7, "x_0": 7, "ioo": [7, 8], "tendsto\u2081": 7, "tendsto": 7, "lim_": 7, "sourc": 7, "abstractli": 7, "salient": 7, "pushforward": 7, "f_": 7, "tendsto\u2082": 7, "via": 7, "leverag": 7, "map_mono": 7, "map_map": 7, "shot": 7, "256": 7, "pullback": 7, "comap": 7, "map_le_iff_le_comap": 7, "contravari": 7, "comap_comap": 7, "plane": 7, "\u02e2": 7, "nhds_prod_eq": 7, "aforement": 7, "le_inf_iff": 7, "attop": 7, "shouldn": 7, "prohibit": 7, "global": 7, "precondit": 7, "closur": 7, "ne_bot": 7, "tour": [7, 8], "claim": 7, "recaptur": 7, "superfici": 7, "stronger": 7, "famili": [7, 8], "\u03b9": [7, 8], "select": 7, "hasbasi": 7, "nhds_basis_ioo_po": 7, "has_basi": 7, "tendsto_iff": 7, "reformul": 7, "ici": 7, "attop_basi": 7, "knew": 7, "gave": 7, "n_p": 7, "n_q": 7, "tiresom": 7, "\u1da0": [7, 8], "superscript": 7, "hp": 7, "hq": 7, "eventually_eq": 7, "tendsto_congr": 7, "review": 7, "eventually_of_foral": 7, "mono": 7, "item": 7, "filter_upward": 7, "hr": 7, "reader": 7, "ae": 7, "aka": 7, "occasion": 7, "frequent": 7, "sophist": 7, "mem_closure_of_tendsto": 7, "cluster_pt": 7, "mem_closure_iff_clusterpt": 7, "le_principal_iff": 7, "nebot_of_l": 7, "hux": 7, "hum": 7, "dist_eq_zero": 7, "emetricspac": 7, "pseudometricspac": 7, "pseudoemetricspac": 7, "journei": 7, "recast": 7, "tendsto_attop": 7, "continuous_iff": 7, "devot": 7, "uncurri": 7, "slow": 7, "continuous_fst": 7, "comp": 7, "assembl": 7, "prod_mk": 7, "continuous_snd": 7, "continuous_dist": 7, "clunki": 7, "crucial": 7, "elabor": 7, "prod_map": 7, "sad": 7, "border": 7, "obfusc": 7, "continuous_pow": 7, "continuousat": 7, "continuousat_iff": 7, "geometr": 7, "closedbal": 7, "radiu": 7, "mem_ball_self": 7, "mem_closedball_self": 7, "isopen": 7, "isopen_iff": 7, "Their": [7, 8], "isclos": [7, 8], "s\u1d9c": 7, "isopen_compl_iff": 7, "hu": [7, 8], "mem_of_tendsto": 7, "mem_closure_iff": 7, "mem_closure_iff_seq_limit": 7, "nhds_basis_bal": 7, "nhds_basis_closedbal": 7, "mem_iff": 7, "segment": 7, "somewher": 7, "continuouson": [7, 8], "minimum": 7, "iscompact": 7, "icc": [7, 8], "iscompact_icc": 7, "\u03c6": 7, "strictmono": 7, "tendsto_subseq": 7, "exists_forall_l": 7, "exists_forall_g": 7, "compactspac": 7, "iscompact_univ": 7, "cauchi": 7, "uniformcontinu": 7, "uniformcontinuous_iff": 7, "clearli": 7, "isclosed_l": 7, "eq_empty_or_nonempti": 7, "attain": 7, "closer": 7, "cauchyseq": 7, "cauchyseq_iff": 7, "completespac": [7, 8], "cauchyseq_tendsto_of_complet": 7, "criterion": 7, "explan": 7, "tendsto_pow_attop_nhds_0_of_lt_1": 7, "dist_le_range_sum_dist": 7, "cauchyseq_of_le_geometric_two": 7, "\u03b5_po": [7, 8], "le_iff_exists_add": 7, "boss": 7, "bair": [7, 8], "exclam": 7, "induct": [7, 11], "rec_on": 7, "ho": 7, "hd": 7, "dens": 7, "densiti": 7, "\u03b4po": 7, "hpo": 7, "hball": 7, "mem_closure_iff_nhds_basi": 7, "recon": 7, "rpo": 7, "rb": 7, "incl": 7, "cdist": 7, "ylim": 7, "yball": 7, "categor": 7, "ignor": 7, "topologicalspac": [7, 8], "isopen_univ": 7, "isopen_empti": 7, "isopen_iunion": 7, "fintyp": 7, "isopen_iint": 7, "continuous_def": 7, "attach": 7, "filteri": 7, "sent": 7, "mem_nhds_iff": 7, "digress": 7, "pure_le_nhd": 7, "eventually_eventually_nhd": 7, "topological_spac": 7, "mk_of_nhd": 7, "nhds_mk_of_nhd": 7, "clean": 7, "fonctori": 7, "induc": 7, "sensibl": 7, "uncount": 7, "relatedli": 7, "coinduc": 7, "t_x": 7, "t_y": 7, "coinduced_le_iff_le_induc": 7, "covari": 7, "coinduced_compos": 7, "induced_compos": 7, "topological_structur": 7, "focus": 7, "nhd": 7, "recov": 7, "foward": 7, "continuous_iff_coinduced_l": 7, "g_": 7, "t_z": 7, "wasn": 7, "\u03c0": [7, 8], "papar": 7, "t_": 7, "x_i": 7, "pi": 7, "functori": 7, "price": 7, "patholog": 7, "t2_space": 7, "hausdorff": 7, "t2space": 7, "tendsto_nhds_uniqu": 7, "regularspac": 7, "closed_nhds_basi": 7, "nhds_basis_open": 7, "denseinduc": 7, "continuousat_extend": 7, "funni": 7, "_in": 7, "nhds_induc": 7, "is_open": 7, "fortiori": 7, "f_cont": 7, "tendsto_right_iff": 7, "firstcountabletopologi": 7, "cluster": 7, "clusterpt": 7, "nebot": 7, "hfx": 7, "push_pul": 7, "of_map": 7, "f_ne": 7, "f_le": 7, "map_eq": 7, "hne": 7, "hle": 7, "huo": 7, "hsu": 7, "elim_finite_subcov": 7, "9": 8, "introductori": 8, "sin": 8, "hasderivat": 8, "hasderivat_sin": 8, "differentiable_at": 8, "differentiableat": 8, "inconveni": 8, "deriv_zero_of_not_differentiableat": 8, "deriv_add": 8, "islocalmin": 8, "deriv_eq_zero": 8, "ev": 8, "roll": 8, "weirder": 8, "hab": 8, "hfc": 8, "hfi": 8, "exists_deriv_eq_zero": 8, "differentiableon": 8, "exists_deriv_eq_slop": 8, "normedaddcommgroup": 8, "norm_add_l": 8, "infer_inst": 8, "normed_spac": 8, "normed_add_group": 8, "stipul": 8, "normedspac": 8, "norm_smul": 8, "banach": 8, "dimension": 8, "finitedimension": 8, "\ud835\udd5c": 8, "nontriviallynormedfield": 8, "normedfield": 8, "exists_one_lt_norm": 8, "nondiscret": 8, "continuouslinearmap": 8, "cont": 8, "map_smul": 8, "le_op_norm": 8, "hmp": 8, "op_norm_le_bound": 8, "steinhau": 8, "bounded": 8, "uniformli": 8, "nonempty_interior_of_union_of_clos": 8, "continuous_linear_map": 8, "op_norm_le_of_shel": 8, "interior_subset": 8, "interior_inter_subset": 8, "is_closed_l": 8, "hc": 8, "h\u03b5": 8, "real_norm_l": 8, "\u03b5k_po": 8, "o": 8, "normedgroup": 8, "isbigowith": 8, "isbigowith_iff": 8, "isbigo_iff_isbigowith": 8, "islittleo_iff_forall_isbigowith": 8, "has_fderiv_at": 8, "fderiv": 8, "fr\u00e9chet": 8, "hasfderivat": 8, "hff": 8, "iter": 8, "multilinear": 8, "with_top": 8, "infti": 8, "cont_diff": 8, "iteratedfderiv": 8, "withtop": 8, "contdiff": 8, "contdiff_iff_continuous_differenti": 8, "stricter": 8, "has_strict_fderiv_at": 8, "\ud835\udd42": 8, "isrorc": 8, "contdiffat": 8, "hasstrictfderivat": 8, "localinvers": 8, "eventually_left_invers": 8, "eventually_right_invers": 8, "to_localinvers": 8, "hasfderivwithinat": 8, "hasfderivatfilt": 8, "overview": 11, "converg": 11, "schr\u00f6der": 11, "bernstein": 11, "irrat": 11, "differenti": 11}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"introduct": 0, "get": 0, "start": 0, "overview": 0, "basic": [1, 6], "calcul": 1, "prove": 1, "ident": 1, "algebra": [1, 5], "structur": [1, 5], "us": 1, "theorem": [1, 3], "lemma": 1, "more": 1, "order": 1, "divis": 1, "fact": 1, "about": 1, "logic": 2, "implic": 2, "univers": 2, "quantifi": 2, "The": [2, 3], "existenti": 2, "negat": 2, "conjunct": 2, "bi": 2, "disjunct": 2, "sequenc": 2, "converg": [2, 7], "set": [3, 7], "function": [3, 7], "schr\u00f6der": 3, "bernstein": 3, "number": 4, "theori": [4, 9], "irrat": 4, "root": 4, "induct": 4, "recurs": 4, "infinit": 4, "mani": 4, "prime": 4, "defin": 5, "build": 5, "gaussian": 5, "integ": 5, "hierarchi": 6, "morphism": 6, "sub": 6, "object": 6, "topologi": 7, "filter": 7, "metric": 7, "space": [7, 8], "continu": [7, 8], "ball": 7, "open": 7, "close": 7, "compact": 7, "uniformli": 7, "complet": 7, "topolog": 7, "fundament": 7, "separ": 7, "countabl": 7, "differenti": 8, "calculu": 8, "elementari": 8, "norm": 8, "linear": 8, "map": 8, "asymptot": 8, "comparison": 8, "integr": 9, "measur": 9, "index": 10, "mathemat": 11, "lean": 11}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 57}, "alltitles": {"Introduction": [[0, "introduction"]], "Getting Started": [[0, "getting-started"]], "Overview": [[0, "overview"]], "Basics": [[1, "basics"], [6, "basics"]], "Calculating": [[1, "calculating"]], "Proving Identities in Algebraic Structures": [[1, "proving-identities-in-algebraic-structures"]], "Using Theorems and Lemmas": [[1, "using-theorems-and-lemmas"]], "More on Order and Divisibility": [[1, "more-on-order-and-divisibility"]], "Proving Facts about Algebraic Structures": [[1, "proving-facts-about-algebraic-structures"]], "Logic": [[2, "logic"]], "Implication and the Universal Quantifier": [[2, "implication-and-the-universal-quantifier"]], "The Existential Quantifier": [[2, "the-existential-quantifier"]], "Negation": [[2, "negation"]], "Conjunction and Bi-implication": [[2, "conjunction-and-bi-implication"]], "Disjunction": [[2, "disjunction"]], "Sequences and Convergence": [[2, "sequences-and-convergence"]], "Sets and Functions": [[3, "sets-and-functions"]], "Sets": [[3, "sets"]], "Functions": [[3, "functions"]], "The Schr\u00f6der-Bernstein Theorem": [[3, "the-schroder-bernstein-theorem"]], "Number Theory": [[4, "number-theory"]], "Irrational Roots": [[4, "irrational-roots"]], "Induction and Recursion": [[4, "induction-and-recursion"]], "Infinitely Many Primes": [[4, "infinitely-many-primes"]], "Structures": [[5, "structures"]], "Defining structures": [[5, "defining-structures"]], "Algebraic Structures": [[5, "algebraic-structures"]], "Building the Gaussian Integers": [[5, "building-the-gaussian-integers"]], "Hierarchies": [[6, "hierarchies"]], "Morphisms": [[6, "morphisms"]], "Sub-objects": [[6, "sub-objects"]], "Topology": [[7, "index-0"]], "Filters": [[7, "filters"]], "Metric spaces": [[7, "metric-spaces"]], "Convergence and continuity": [[7, "convergence-and-continuity"]], "Balls, open sets and closed sets": [[7, "balls-open-sets-and-closed-sets"]], "Compactness": [[7, "compactness"], [7, "id5"]], "Uniformly continuous functions": [[7, "uniformly-continuous-functions"]], "Completeness": [[7, "completeness"]], "Topological spaces": [[7, "topological-spaces"]], "Fundamentals": [[7, "fundamentals"]], "Separation and countability": [[7, "separation-and-countability"]], "Differential Calculus": [[8, "index-0"]], "Elementary Differential Calculus": [[8, "elementary-differential-calculus"]], "Differential Calculus in Normed Spaces": [[8, "differential-calculus-in-normed-spaces"]], "Normed spaces": [[8, "id3"]], "Continuous linear maps": [[8, "continuous-linear-maps"]], "Asymptotic comparisons": [[8, "asymptotic-comparisons"]], "Differentiability": [[8, "differentiability"]], "Integration and Measure Theory": [[9, "index-0"]], "Index": [[10, "index"]], "Mathematics in Lean": [[11, "mathematics-in-lean"]]}, "indexentries": {"check": [[0, "index-0"]], "commands": [[0, "index-0"]], "abel": [[1, "index-14"]], "absolute value": [[1, "index-23"]], "apply": [[1, "index-16"]], "calc": [[1, "index-3"]], "command": [[1, "index-9"]], "commutative ring": [[1, "index-8"]], "definitional equality": [[1, "index-12"]], "divisibility": [[1, "index-24"]], "exact": [[1, "index-5"]], "exponential": [[1, "index-18"]], "gcd": [[1, "index-25"]], "goal": [[1, "index-2"]], "group": [[1, "index-14"]], "group (algebraic structure)": [[1, "index-13"]], "group (tactic)": [[1, "index-14"]], "have": [[1, "index-11"], [2, "index-12"]], "implicit argument": [[1, "index-10"]], "inequalities": [[1, "index-15"]], "lattice": [[1, "index-27"]], "lcm": [[1, "index-25"]], "linarith": [[1, "index-17"]], "local context": [[1, "index-2"]], "logarithm": [[1, "index-18"]], "max": [[1, "index-20"]], "metric space": [[1, "index-28"], [7, "index-2"]], "min": [[1, "index-20"]], "namespace": [[1, "index-9"]], "noncomm_ring": [[1, "index-14"]], "norm_num": [[1, "index-19"]], "open": [[1, "index-9"]], "order relation": [[1, "index-26"]], "partial order": [[1, "index-26"]], "proof state": [[1, "index-2"]], "real numbers": [[1, "index-1"]], "refl and reflexivity": [[1, "index-12"]], "reflexivity": [[1, "index-12"]], "repeat": [[1, "index-22"]], "rewrite": [[1, "index-0"]], "rfl": [[1, "index-12"]], "ring": [[1, "index-6"]], "ring (algebraic structure)": [[1, "index-7"]], "ring (tactic)": [[1, "index-6"]], "rw": [[1, "index-0"], [1, "index-4"]], "rw and rewrite": [[1, "index-0"], [1, "index-4"]], "show": [[1, "index-21"]], "tactics": [[1, "index-0"], [1, "index-11"], [1, "index-12"], [1, "index-14"], [1, "index-16"], [1, "index-17"], [1, "index-19"], [1, "index-21"], [1, "index-22"], [1, "index-3"], [1, "index-4"], [1, "index-5"], [1, "index-6"], [2, "index-0"], [2, "index-12"], [2, "index-13"], [2, "index-14"], [2, "index-15"], [2, "index-16"], [2, "index-17"], [2, "index-18"], [2, "index-19"], [2, "index-2"], [2, "index-20"], [2, "index-21"], [2, "index-23"], [2, "index-24"], [2, "index-25"], [2, "index-26"], [2, "index-4"], [2, "index-6"], [2, "index-8"], [2, "index-9"], [3, "index-1"], [3, "index-2"], [7, "index-3"]], "absurd": [[2, "index-17"]], "anonymous constructor": [[2, "index-7"]], "assumption": [[2, "index-19"]], "by_cases": [[2, "index-23"]], "by_contra": [[2, "index-14"]], "by_contra and by_contradiction": [[2, "index-14"]], "cases": [[2, "index-8"]], "change": [[2, "index-2"]], "congr": [[2, "index-25"]], "constructor": [[2, "index-18"]], "contradiction": [[2, "index-17"]], "contrapose": [[2, "index-16"]], "convert": [[2, "index-26"]], "dsimp": [[2, "index-2"]], "erw": [[2, "index-4"]], "excluded middle": [[2, "index-22"]], "exfalso": [[2, "index-17"]], "ext": [[2, "index-24"]], "extensionality": [[2, "index-24"]], "field_simp": [[2, "index-11"]], "from": [[2, "index-12"]], "injective function": [[2, "index-5"]], "intro": [[2, "index-0"]], "lambda abstraction": [[2, "index-1"]], "left": [[2, "index-21"]], "let": [[2, "index-13"]], "monotone function": [[2, "index-3"]], "push_neg": [[2, "index-15"]], "rcases": [[2, "index-9"]], "right": [[2, "index-21"]], "rintro": [[2, "index-9"]], "simp": [[2, "index-20"], [3, "index-1"]], "surjective function": [[2, "index-10"]], "tactic": [[2, "index-11"]], "this": [[2, "index-12"]], "use": [[2, "index-6"]], "bounded quantifiers": [[3, "index-3"]], "rwa": [[3, "index-2"]], "set operations": [[3, "index-0"]], "filter": [[7, "index-1"]], "continuity": [[7, "index-3"]], "topological space": [[7, "index-4"]], "topology": [[7, "index-0"]], "differential calculus": [[8, "index-0"]], "elementary calculus": [[8, "index-1"]], "normed space": [[8, "index-2"]], "integration": [[9, "index-0"]]}})
-
-
-
@@ -1,1 +1,27 @@../lake-manifest.json {"version": 4, "packagesDir": "lake-packages", "packages": [{"git": {"url": "https://github.com/leanprover-community/mathlib4", "subDir?": null, "rev": "2db7650f98b1ea3543e48b6b02aa9112e33bb68b", "name": "mathlib", "inputRev?": "master"}}, {"git": {"url": "https://github.com/gebner/quote4", "subDir?": null, "rev": "c71f94e34c1cda52eef5c93dc9da409ab2727420", "name": "Qq", "inputRev?": "master"}}, {"git": {"url": "https://github.com/JLimperg/aesop", "subDir?": null, "rev": "ca73109cc40837bc61df8024c9016da4b4f99d4c", "name": "aesop", "inputRev?": "master"}}, {"git": {"url": "https://github.com/leanprover/std4", "subDir?": null, "rev": "6932c4ea52914dc6b0488944e367459ddc4d01a6", "name": "std", "inputRev?": "main"}}]}
-
-
-
@@ -1,1 +1,13 @@../lakefile.lean import Lake open Lake DSL package mil { -- add package configuration options here } @[default_target] lean_lib MIL { -- add library configuration options here } require mathlib from git "https://github.com/leanprover-community/mathlib4"@"master"
-
-
-
@@ -1,1 +1,1 @@../lean-toolchain leanprover/lean4:nightly-2023-05-31
-
-