Article I: Sets, maps, composition
Until the introduction of the definition of category at the end of Article I, we implement all maps in the book as Lean functions.
Check to be sure you understand how we got diagrams (ii) and (iii) from the given diagram (i). Then fill in (iv) and (v) yourself, starting over from (i). Then check to see that (v) and (iii) are the same.
Solution: Exercise 1
For simplicity, we use types here instead of sets. We number the elements in each set/type from top to bottom (top left to bottom right for D).
inductive A
| a₁ | a₂ | a₃
inductive B
| b₁ | b₂ | b₃ | b₄
inductive C
| c₁ | c₂ | c₃ | c₄ | c₅
inductive D
| d₁ | d₂ | d₃ | d₄ | d₅ | d₆
def f : A → B
| A.a₁ => B.b₁
| A.a₂ => B.b₂
| A.a₃ => B.b₃
def g : B → C
| B.b₁ => C.c₂
| B.b₂ => C.c₂
| B.b₃ => C.c₄
| B.b₄ => C.c₅
def h : C → D
| C.c₁ => D.d₁
| C.c₂ => D.d₁
| C.c₃ => D.d₃
| C.c₄ => D.d₃
| C.c₅ => D.d₅
For diagram (iv), we have f as above and {h \circ g} as follows:
def hg : B → D
| B.b₁ => D.d₁
| B.b₂ => D.d₁
| B.b₃ => D.d₃
| B.b₄ => D.d₅
example : hg = h ∘ g := ⊢ hg = h ∘ g
x:B⊢ hg x = (h ∘ g) x
⊢ hg B.b₁ = (h ∘ g) B.b₁⊢ hg B.b₂ = (h ∘ g) B.b₂⊢ hg B.b₃ = (h ∘ g) B.b₃⊢ hg B.b₄ = (h ∘ g) B.b₄ ⊢ hg B.b₁ = (h ∘ g) B.b₁⊢ hg B.b₂ = (h ∘ g) B.b₂⊢ hg B.b₃ = (h ∘ g) B.b₃⊢ hg B.b₄ = (h ∘ g) B.b₄ All goals completed! 🐙
For diagram (v), we have {(h \circ g) \circ f} as follows, which is indeed the same as {h \circ (g \circ f)} in diagram (iii):
def hgf : A → D
| A.a₁ => D.d₁
| A.a₂ => D.d₁
| A.a₃ => D.d₃
example : hgf = (h ∘ g) ∘ f := ⊢ hgf = (h ∘ g) ∘ f
x:A⊢ hgf x = ((h ∘ g) ∘ f) x
⊢ hgf A.a₁ = ((h ∘ g) ∘ f) A.a₁⊢ hgf A.a₂ = ((h ∘ g) ∘ f) A.a₂⊢ hgf A.a₃ = ((h ∘ g) ∘ f) A.a₃ ⊢ hgf A.a₁ = ((h ∘ g) ∘ f) A.a₁⊢ hgf A.a₂ = ((h ∘ g) ∘ f) A.a₂⊢ hgf A.a₃ = ((h ∘ g) ∘ f) A.a₃ All goals completed! 🐙
One very useful sort of set is a 'singleton' set, a set with exactly one element.... Call this set '\mathbf{1}'.
We define \mathbf{1} in Lean as the finite set containing the single element of type Unit.
namespace CM_Finset
def One : Finset Unit := Finset.univ
end CM_Finset
A point of a set X is a map {\mathbf{1} \rightarrow X}.
We define Point in Lean as a Map between Finsets. (The coercion allows a term inhabiting Map to be used directly as a function, so we can write f, John, and eggs below rather than f.toFun, John.toFun, and eggs.toFun.)
namespace CM_Finset
structure Map {α β : Type*} (X : Finset α) (Y : Finset β) where
toFun : α → β
maps_to_codomain : ∀ a : α, a ∈ X → toFun a ∈ Y
instance {α β : Type*} (X : Finset α) (Y : Finset β)
: CoeFun (Map X Y) (fun _ ↦ α → β) where
coe F := F.toFun
abbrev Point {β : Type*} (Y : Finset β) := Map One Y
end CM_Finset
Since a point is a map, we can compose it with another map, and get a point again.
We provide a Lean implementation below of the example given in the book on p. 19.
namespace CM_Finset
def A : Finset String := { "John", "Mary", "Sam" }
def B : Finset String := { "eggs", "coffee" }
def John : Point A := {
toFun := fun _ ↦ "John"
maps_to_codomain := ⊢ ∀ a ∈ One, "John" ∈ A All goals completed! 🐙
}
def f : Map A B := {
toFun
| "John" => "eggs"
| "Mary" => "eggs"
| _ => "coffee"
maps_to_codomain := ⊢ ∀ a ∈ A,
(match a with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") ∈
B
intro _ a✝:Stringha:a✝ ∈ A⊢ (match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") ∈
B
a✝:Stringha:a✝ ∈ {"John", "Mary", "Sam"}⊢ (match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") ∈
{"eggs", "coffee"}
repeat a✝:Stringha:a✝ = "John" ∨ a✝ = "Mary" ∨ a✝ ∈ {"Sam"}⊢ (match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") ∈
{"coffee"}
a✝:Stringha:a✝ = "John" ∨ a✝ = "Mary" ∨ a✝ = "Sam"⊢ (match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"coffee"
a✝:Stringha:a✝ = "John"⊢ (match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"coffee"a✝:Stringha:a✝ = "Mary"⊢ (match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"coffee"a✝:Stringha:a✝ = "Sam"⊢ (match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"coffee"
all_goals
⊢ (match "Sam" with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"eggs" ∨
(match "Sam" with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"coffee"
first | ⊢ (match "Sam" with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"eggs" ∨
(match "Sam" with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"coffee" | All goals completed! 🐙
}
def eggs : Point B := {
toFun := fun _ ↦ "eggs"
maps_to_codomain := ⊢ ∀ a ∈ One, "eggs" ∈ B All goals completed! 🐙
}
example : f ∘ John = eggs := rfl
end CM_Finset
Replacing Finset with Set broadens the application to any set, not just finite sets.
namespace CM_Set
def One : Set Unit := Set.univ
structure Map {α β : Type*} (X : Set α) (Y : Set β) where
toFun : α → β
maps_to_codomain : ∀ a : α, a ∈ X → toFun a ∈ Y
instance {α β : Type*} (X : Set α) (Y : Set β)
: CoeFun (Map X Y) (fun _ ↦ α → β) where
coe F := F.toFun
abbrev Point {β : Type*} (Y : Set β) := Map One Y
def A : Set String := { "John", "Mary", "Sam" }
def B : Set String := { "eggs", "coffee" }
def John : Point A := {
toFun := fun _ ↦ "John"
maps_to_codomain := ⊢ ∀ a ∈ One, "John" ∈ A All goals completed! 🐙
}
def f : Map A B := {
toFun
| "John" => "eggs"
| "Mary" => "eggs"
| _ => "coffee"
maps_to_codomain := ⊢ ∀ a ∈ A,
(match a with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") ∈
B
intro _ a✝:Stringha:a✝ ∈ A⊢ (match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") ∈
B
a✝:Stringha:a✝ ∈ {"John", "Mary", "Sam"}⊢ (match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") ∈
{"eggs", "coffee"}
repeat a✝:Stringha:a✝ = "John" ∨ a✝ = "Mary" ∨ a✝ ∈ {"Sam"}⊢ (match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") ∈
{"coffee"}
a✝:Stringha:a✝ = "John" ∨ a✝ = "Mary" ∨ a✝ = "Sam"⊢ (match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"coffee"
a✝:Stringha:a✝ = "John"⊢ (match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"coffee"a✝:Stringha:a✝ = "Mary"⊢ (match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"coffee"a✝:Stringha:a✝ = "Sam"⊢ (match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"coffee"
all_goals
⊢ (match "Sam" with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"eggs" ∨
(match "Sam" with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"coffee"
first | ⊢ (match "Sam" with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"eggs" ∨
(match "Sam" with
| "John" => "eggs"
| "Mary" => "eggs"
| x => "coffee") =
"coffee" | All goals completed! 🐙
}
def eggs : Point B := {
toFun := fun _ ↦ "eggs"
maps_to_codomain := ⊢ ∀ a ∈ One, "eggs" ∈ B All goals completed! 🐙
}
example : f ∘ John = eggs := rfl
end CM_Set
Using types instead of sets is cleaner and further broadens the application to any type, not just sets.
def One := Unit
namespace CM_Type
def Point (Y : Type) := One → Y
def A := { a : String // a = "John" ∨ a = "Mary" ∨ a = "Sam" }
def B := { b : String // b = "eggs" ∨ b = "coffee" }
def John : Point A := fun _ ↦ ⟨"John", x✝:One⊢ "John" = "John" ∨ "John" = "Mary" ∨ "John" = "Sam" All goals completed! 🐙⟩
def f : A → B := fun a ↦
match a.val with
| "John" => ⟨"eggs", a:A⊢ "eggs" = "eggs" ∨ "eggs" = "coffee" All goals completed! 🐙⟩
| "Mary" => ⟨"eggs", a:A⊢ "eggs" = "eggs" ∨ "eggs" = "coffee" All goals completed! 🐙⟩
| _ => ⟨"coffee", a:Ax✝:String⊢ "coffee" = "eggs" ∨ "coffee" = "coffee" All goals completed! 🐙⟩
def eggs : Point B := fun _ ↦ ⟨"eggs", x✝:One⊢ "eggs" = "eggs" ∨ "eggs" = "coffee" All goals completed! 🐙⟩
example : f ∘ John = eggs := rfl
end CM_Type
We lift our definition for the function Point between types to the morphism Point in the category Type for later use. Note the application of ⟶ (\hom) for the morphism type instead of → (\r) for the function arrow.
def Point (Y : Type) := One ⟶ Y
For Exercises 2–5 which follow, rather than providing exhaustive lists of maps, it seems more useful at this stage to introduce what the book calls Alysia's formula, even though that formula doesn't appear until slightly later (on pp. 33–34). The formula states that the number of different maps between two finite sets is equal to the number of elements in the codomain raised to the power of the number of elements in the domain — that is, the number of maps is {(\#\beta)^{(\#\alpha)}}, where {\#\alpha} is the size of the domain \alpha and {\#\beta} is the size of the codomain \beta.
def Alysia's_formula (α β : Type*) [Fintype α] [Fintype β] : ℕ :=
Fintype.card β ^ Fintype.card α
How many different maps f are there with domain A and codomain B?
Solution: Exercise 2
By Alysia's formula, we have {(\#B)^{(\#A)} = 2^3 = 8} different maps.
open CM_Finset
#eval Alysia's_formula A B
Same, but for maps {A \xrightarrow{f} A}?
Solution: Exercise 3
By Alysia's formula, we have {(\#A)^{(\#A)} = 3^3 = 27} different maps.
open CM_Finset
#eval Alysia's_formula A A
Same, but for maps {B \xrightarrow{f} A}?
Solution: Exercise 4
By Alysia's formula, we have {(\#A)^{(\#B)} = 3^2 = 9} different maps.
open CM_Finset
#eval Alysia's_formula B A
Same, but for maps {B \xrightarrow{f} B}?
Solution: Exercise 5
By Alysia's formula, we have {(\#B)^{(\#B)} = 2^2 = 4} different maps.
open CM_Finset
#eval Alysia's_formula B B
Exercises 6 and 7 concern idempotence, which the book formally introduces later on p. 54. For the purpose of these two exercises (and again aiming to avoid exhaustive lists of maps), we introduce the formula
\sum_{k=0}^{n} {n \choose k} k^{n-k}
for the total number of possible idempotents on a finite set. (See the Wikipedia article on idempotence for additional information.)
def idempotentCount (α : Type) [Fintype α] : ℕ :=
let n := Fintype.card α
∑ k ∈ Finset.range (n + 1), (n.choose k) * k ^ (n - k)
How many maps {A \xrightarrow{f} A} satisfy {f \circ f = f}?
Solution: Exercise 6
By the formula above, we have 10 different maps.
open CM_Finset
#eval idempotentCount A
How many maps {B \xrightarrow{g} B} satisfy {g \circ g = g}?
Solution: Exercise 7
By the formula above, we have 3 different maps.
open CM_Finset
#eval idempotentCount B
Can you find a pair of maps {A \xrightarrow{f} B \xrightarrow{g} A} for which {g \circ f = 1_A}? If so, how many such pairs?
Solution: Exercise 8
No such pair exists, since the image of 1_A has 3 elements, but the image of {g \circ f} has only 2 elements.
open CM_Finset
We will begin using the Lean notation 𝟙 X, for the identity morphism on X, after we finish Article I and start working with morphisms and categories; for now, though, since we are still operating with functions and sets, we must define the identity map on A explicitly.
def idA : Map A A := {
toFun := id
maps_to_codomain := ⊢ ∀ a ∈ A, id a ∈ A
intro _ a✝:Stringha:a✝ ∈ A⊢ id a✝ ∈ A
a✝:Stringha:a✝ ∈ {"John", "Mary", "Sam"}⊢ a✝ ∈ {"John", "Mary", "Sam"}
repeat a✝:Stringha:a✝ = "John" ∨ a✝ = "Mary" ∨ a✝ ∈ {"Sam"}⊢ a✝ = "John" ∨ a✝ = "Mary" ∨ a✝ ∈ {"Sam"}
a✝:Stringha:a✝ = "John" ∨ a✝ = "Mary" ∨ a✝ = "Sam"⊢ a✝ = "John" ∨ a✝ = "Mary" ∨ a✝ = "Sam"
a✝:Stringha:a✝ = "John"⊢ a✝ = "John" ∨ a✝ = "Mary" ∨ a✝ = "Sam"a✝:Stringha:a✝ = "Mary"⊢ a✝ = "John" ∨ a✝ = "Mary" ∨ a✝ = "Sam"a✝:Stringha:a✝ = "Sam"⊢ a✝ = "John" ∨ a✝ = "Mary" ∨ a✝ = "Sam"
all_goals
⊢ "Sam" = "John" ∨ "Sam" = "Mary" ∨ "Sam" = "Sam"
first
| ⊢ "Sam" = "John" ∨ "Sam" = "Mary" ∨ "Sam" = "Sam"
| ⊢ "Sam" = "John" ∨ "Sam" = "Mary" ∨ "Sam" = "Sam"
| All goals completed! 🐙
}
open Finset in
example : ¬(∃ f : Map A B, ∃ g : Map B A, g ∘ f = idA) := ⊢ ¬∃ f g, g.toFun ∘ f.toFun = idA.toFun
-- Convert to the equivalent statement ∀ f g, g ∘ f ≠ idA
⊢ ∀ (f : Map A B) (g : Map B A), g.toFun ∘ f.toFun ≠ idA.toFun
-- Assume that g ∘ f = idA for some f, g, and derive a contradiction
intro f f:Map A Bg:Map B A⊢ g.toFun ∘ f.toFun ≠ idA.toFun f:Map A Bg:Map B Ah_eq:g.toFun ∘ f.toFun = idA.toFun⊢ False
-- Since the functions g ∘ f and idA are equal, so are their images
have h_img_eq
: (image g (image f A)).card = (image idA A).card := ⊢ ¬∃ f g, g.toFun ∘ f.toFun = idA.toFun
All goals completed! 🐙
-- But the image of g(f(A)) has at most 2 elements,
have h_card_gfA : (image g (image f A)).card ≤ 2 := ⊢ ¬∃ f g, g.toFun ∘ f.toFun = idA.toFun
f:Map A Bg:Map B Ah_eq:g.toFun ∘ f.toFun = idA.toFunh_img_eq:#(image g.toFun (image f.toFun A)) = #(image idA.toFun A) :=
Eq.mpr (id (congrArg (fun _a ↦ #_a = #(image idA.toFun A)) image_image))
(Eq.mpr (id (congrArg (fun _a ↦ #(image _a A) = #(image idA.toFun A)) h_eq)) (Eq.refl #(image idA.toFun A)))⊢ #(image g.toFun (image f.toFun A)) ≤ ?bf:Map A Bg:Map B Ah_eq:g.toFun ∘ f.toFun = idA.toFunh_img_eq:#(image g.toFun (image f.toFun A)) = #(image idA.toFun A) :=
Eq.mpr (id (congrArg (fun _a ↦ #_a = #(image idA.toFun A)) image_image))
(Eq.mpr (id (congrArg (fun _a ↦ #(image _a A) = #(image idA.toFun A)) h_eq)) (Eq.refl #(image idA.toFun A)))⊢ ?b ≤ 2f:Map A Bg:Map B Ah_eq:g.toFun ∘ f.toFun = idA.toFunh_img_eq:#(image g.toFun (image f.toFun A)) = #(image idA.toFun A) :=
Eq.mpr (id (congrArg (fun _a ↦ #_a = #(image idA.toFun A)) image_image))
(Eq.mpr (id (congrArg (fun _a ↦ #(image _a A) = #(image idA.toFun A)) h_eq)) (Eq.refl #(image idA.toFun A)))⊢ ℕ
f:Map A Bg:Map B Ah_eq:g.toFun ∘ f.toFun = idA.toFunh_img_eq:#(image g.toFun (image f.toFun A)) = #(image idA.toFun A) :=
Eq.mpr (id (congrArg (fun _a ↦ #_a = #(image idA.toFun A)) image_image))
(Eq.mpr (id (congrArg (fun _a ↦ #(image _a A) = #(image idA.toFun A)) h_eq)) (Eq.refl #(image idA.toFun A)))⊢ #(image g.toFun (image f.toFun A)) ≤ ?b All goals completed! 🐙
f:Map A Bg:Map B Ah_eq:g.toFun ∘ f.toFun = idA.toFunh_img_eq:#(image g.toFun (image f.toFun A)) = #(image idA.toFun A) :=
Eq.mpr (id (congrArg (fun _a ↦ #_a = #(image idA.toFun A)) image_image))
(Eq.mpr (id (congrArg (fun _a ↦ #(image _a A) = #(image idA.toFun A)) h_eq)) (Eq.refl #(image idA.toFun A)))⊢ ?b ≤ 2 f:Map A Bg:Map B Ah_eq:g.toFun ∘ f.toFun = idA.toFunh_img_eq:#(image g.toFun (image f.toFun A)) = #(image idA.toFun A) :=
Eq.mpr (id (congrArg (fun _a ↦ #_a = #(image idA.toFun A)) image_image))
(Eq.mpr (id (congrArg (fun _a ↦ #(image _a A) = #(image idA.toFun A)) h_eq)) (Eq.refl #(image idA.toFun A)))⊢ #(image f.toFun A) ≤ #B
f:Map A Bg:Map B Ah_eq:g.toFun ∘ f.toFun = idA.toFunh_img_eq:#(image g.toFun (image f.toFun A)) = #(image idA.toFun A) :=
Eq.mpr (id (congrArg (fun _a ↦ #_a = #(image idA.toFun A)) image_image))
(Eq.mpr (id (congrArg (fun _a ↦ #(image _a A) = #(image idA.toFun A)) h_eq)) (Eq.refl #(image idA.toFun A)))⊢ image f.toFun A ⊆ B
intro _ f:Map A Bg:Map B Ah_eq:g.toFun ∘ f.toFun = idA.toFunh_img_eq:#(image g.toFun (image f.toFun A)) = #(image idA.toFun A) :=
Eq.mpr (id (congrArg (fun _a ↦ #_a = #(image idA.toFun A)) image_image))
(Eq.mpr (id (congrArg (fun _a ↦ #(image _a A) = #(image idA.toFun A)) h_eq)) (Eq.refl #(image idA.toFun A)))a✝:Stringhfa:a✝ ∈ image f.toFun A⊢ a✝ ∈ B
f:Map A Bg:Map B Ah_eq:g.toFun ∘ f.toFun = idA.toFunh_img_eq:#(image g.toFun (image f.toFun A)) = #(image idA.toFun A) :=
Eq.mpr (id (congrArg (fun _a ↦ #_a = #(image idA.toFun A)) image_image))
(Eq.mpr (id (congrArg (fun _a ↦ #(image _a A) = #(image idA.toFun A)) h_eq)) (Eq.refl #(image idA.toFun A)))a✝:Stringhfa:∃ a ∈ A, f.toFun a = a✝⊢ a✝ ∈ B
f:Map A Bg:Map B Ah_eq:g.toFun ∘ f.toFun = idA.toFunh_img_eq:#(image g.toFun (image f.toFun A)) = #(image idA.toFun A) :=
Eq.mpr (id (congrArg (fun _a ↦ #_a = #(image idA.toFun A)) image_image))
(Eq.mpr (id (congrArg (fun _a ↦ #(image _a A) = #(image idA.toFun A)) h_eq)) (Eq.refl #(image idA.toFun A)))a:Stringha:a ∈ A⊢ f.toFun a ∈ B
All goals completed! 🐙
-- while the image of idA(A) has 3 elements
f:Map A Bg:Map B Ah_eq:g.toFun ∘ f.toFun = idA.toFunh_img_eq:#(image g.toFun (image f.toFun A)) = #(image idA.toFun A) :=
Eq.mpr (id (congrArg (fun _a ↦ #_a = #(image idA.toFun A)) image_image))
(Eq.mpr (id (congrArg (fun _a ↦ #(image _a A) = #(image idA.toFun A)) h_eq)) (Eq.refl #(image idA.toFun A)))h_card_gfA:#(image g.toFun (image f.toFun A)) ≤ 2 :=
le_trans card_image_le
(id
(card_le_card fun ⦃a⦄ hfa ↦
Exists.casesOn (Eq.mp (congrArg (fun _a ↦ _a) (propext mem_image)) hfa) fun a_1 h ↦
And.casesOn h fun ha right ↦ right ▸ f.maps_to_codomain a_1 ha))h_card_idA:#(image idA.toFun A) = 3 := rfl⊢ False
-- So we have a contradiction
f:Map A Bg:Map B Ah_eq:g.toFun ∘ f.toFun = idA.toFunh_img_eq:#(image g.toFun (image f.toFun A)) = #(image idA.toFun A) :=
Eq.mpr (id (congrArg (fun _a ↦ #_a = #(image idA.toFun A)) image_image))
(Eq.mpr (id (congrArg (fun _a ↦ #(image _a A) = #(image idA.toFun A)) h_eq)) (Eq.refl #(image idA.toFun A)))h_card_gfA:3 ≤ 2h_card_idA:#(image idA.toFun A) = 3⊢ False
All goals completed! 🐙
Can you find a pair of maps {B \xrightarrow{h} A \xrightarrow{k} B} for which {k \circ h = 1_B}? If so, how many such pairs?
Solution: Exercise 9
We define one pair h, k.
open CM_Finset
def h : Map B A := {
toFun
| "eggs" => "John"
| _ => "Mary"
maps_to_codomain := ⊢ ∀ a ∈ B,
(match a with
| "eggs" => "John"
| x => "Mary") ∈
A
intro _ a✝:Stringhb:a✝ ∈ B⊢ (match a✝ with
| "eggs" => "John"
| x => "Mary") ∈
A
a✝:Stringhb:a✝ ∈ {"eggs", "coffee"}⊢ (match a✝ with
| "eggs" => "John"
| x => "Mary") ∈
{"John", "Mary", "Sam"}
repeat a✝:Stringhb:a✝ = "eggs" ∨ a✝ ∈ {"coffee"}⊢ (match a✝ with
| "eggs" => "John"
| x => "Mary") =
"John" ∨
(match a✝ with
| "eggs" => "John"
| x => "Mary") =
"Mary" ∨
(match a✝ with
| "eggs" => "John"
| x => "Mary") ∈
{"Sam"}
a✝:Stringhb:a✝ = "eggs" ∨ a✝ = "coffee"⊢ (match a✝ with
| "eggs" => "John"
| x => "Mary") =
"John" ∨
(match a✝ with
| "eggs" => "John"
| x => "Mary") =
"Mary" ∨
(match a✝ with
| "eggs" => "John"
| x => "Mary") =
"Sam"
a✝:Stringhb:a✝ = "eggs"⊢ (match a✝ with
| "eggs" => "John"
| x => "Mary") =
"John" ∨
(match a✝ with
| "eggs" => "John"
| x => "Mary") =
"Mary" ∨
(match a✝ with
| "eggs" => "John"
| x => "Mary") =
"Sam"a✝:Stringhb:a✝ = "coffee"⊢ (match a✝ with
| "eggs" => "John"
| x => "Mary") =
"John" ∨
(match a✝ with
| "eggs" => "John"
| x => "Mary") =
"Mary" ∨
(match a✝ with
| "eggs" => "John"
| x => "Mary") =
"Sam"
all_goals
⊢ (match "coffee" with
| "eggs" => "John"
| x => "Mary") =
"John" ∨
(match "coffee" with
| "eggs" => "John"
| x => "Mary") =
"Mary" ∨
(match "coffee" with
| "eggs" => "John"
| x => "Mary") =
"Sam"
first | ⊢ (match "coffee" with
| "eggs" => "John"
| x => "Mary") =
"John" ∨
(match "coffee" with
| "eggs" => "John"
| x => "Mary") =
"Mary" ∨
(match "coffee" with
| "eggs" => "John"
| x => "Mary") =
"Sam" | All goals completed! 🐙
}
def k : Map A B := {
toFun
| "John" => "eggs"
| _ => "coffee"
maps_to_codomain := ⊢ ∀ a ∈ A,
(match a with
| "John" => "eggs"
| x => "coffee") ∈
B
intro _ a✝:Stringha:a✝ ∈ A⊢ (match a✝ with
| "John" => "eggs"
| x => "coffee") ∈
B
a✝:Stringha:a✝ ∈ {"John", "Mary", "Sam"}⊢ (match a✝ with
| "John" => "eggs"
| x => "coffee") ∈
{"eggs", "coffee"}
repeat a✝:Stringha:a✝ = "John" ∨ a✝ = "Mary" ∨ a✝ ∈ {"Sam"}⊢ (match a✝ with
| "John" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "John" => "eggs"
| x => "coffee") ∈
{"coffee"}
a✝:Stringha:a✝ = "John" ∨ a✝ = "Mary" ∨ a✝ = "Sam"⊢ (match a✝ with
| "John" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "John" => "eggs"
| x => "coffee") =
"coffee"
a✝:Stringha:a✝ = "John"⊢ (match a✝ with
| "John" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "John" => "eggs"
| x => "coffee") =
"coffee"a✝:Stringha:a✝ = "Mary"⊢ (match a✝ with
| "John" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "John" => "eggs"
| x => "coffee") =
"coffee"a✝:Stringha:a✝ = "Sam"⊢ (match a✝ with
| "John" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "John" => "eggs"
| x => "coffee") =
"coffee"
all_goals
⊢ (match "Sam" with
| "John" => "eggs"
| x => "coffee") =
"eggs" ∨
(match "Sam" with
| "John" => "eggs"
| x => "coffee") =
"coffee"
first | ⊢ (match "Sam" with
| "John" => "eggs"
| x => "coffee") =
"eggs" ∨
(match "Sam" with
| "John" => "eggs"
| x => "coffee") =
"coffee" | All goals completed! 🐙
}
We define the identity map on B explicitly (see the earlier comment under Exercise 8).
def idB : Map B B := {
toFun
| "eggs" => "eggs"
| _ => "coffee"
maps_to_codomain := ⊢ ∀ a ∈ B,
(match a with
| "eggs" => "eggs"
| x => "coffee") ∈
B
intro _ a✝:Stringhb:a✝ ∈ B⊢ (match a✝ with
| "eggs" => "eggs"
| x => "coffee") ∈
B
a✝:Stringhb:a✝ ∈ {"eggs", "coffee"}⊢ (match a✝ with
| "eggs" => "eggs"
| x => "coffee") ∈
{"eggs", "coffee"}
a✝:Stringhb:a✝ = "eggs" ∨ a✝ = "coffee"⊢ (match a✝ with
| "eggs" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "eggs" => "eggs"
| x => "coffee") =
"coffee"
a✝:Stringhb:a✝ = "eggs"⊢ (match a✝ with
| "eggs" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "eggs" => "eggs"
| x => "coffee") =
"coffee"a✝:Stringhb:a✝ = "coffee"⊢ (match a✝ with
| "eggs" => "eggs"
| x => "coffee") =
"eggs" ∨
(match a✝ with
| "eggs" => "eggs"
| x => "coffee") =
"coffee"
all_goals
⊢ (match "coffee" with
| "eggs" => "eggs"
| x => "coffee") =
"eggs" ∨
(match "coffee" with
| "eggs" => "eggs"
| x => "coffee") =
"coffee"
first | ⊢ (match "coffee" with
| "eggs" => "eggs"
| x => "coffee") =
"eggs" ∨
(match "coffee" with
| "eggs" => "eggs"
| x => "coffee") =
"coffee" | All goals completed! 🐙
}
A proof that {k ∘ h = 1_B} holds for our pair h, k is given below. (We define a macro for a repeated sequence of tactics to keep the proof concise.)
syntax "eval_map" Lean.Parser.Tactic.rwRule : tactic
macro_rules
| `(tactic| eval_map $fn_name) =>
`(tactic| (
rw [$fn_name]
dsimp only [DFunLike.coe]
split
· contradiction
· rfl
)
)
example : k ∘ h = idB := ⊢ k.toFun ∘ h.toFun = idB.toFun
x:String⊢ (k.toFun ∘ h.toFun) x = idB.toFun x
x:String⊢ k.toFun (h.toFun x) = idB.toFun x
x:Stringh_x_eggs:x = "eggs"⊢ k.toFun (h.toFun x) = idB.toFun xx:Stringh_x_eggs:¬x = "eggs"⊢ k.toFun (h.toFun x) = idB.toFun x
x:Stringh_x_eggs:x = "eggs"⊢ k.toFun (h.toFun x) = idB.toFun x x:Stringh_x_eggs:x = "eggs"⊢ k.toFun (h.toFun "eggs") = idB.toFun "eggs"
x:Stringh_x_eggs:x = "eggs"h_eval:h.toFun "eggs" = "John" := rfl⊢ k.toFun (h.toFun "eggs") = idB.toFun "eggs"
x:Stringh_x_eggs:x = "eggs"h_eval:h.toFun "eggs" = "John" := rflk_eval:k.toFun "John" = "eggs" := rfl⊢ k.toFun (h.toFun "eggs") = idB.toFun "eggs"
x:Stringh_x_eggs:x = "eggs"h_eval:h.toFun "eggs" = "John" := rflk_eval:k.toFun "John" = "eggs" := rflidB_eval:idB.toFun "eggs" = "eggs" := rfl⊢ k.toFun (h.toFun "eggs") = idB.toFun "eggs"
All goals completed! 🐙
x:Stringh_x_eggs:¬x = "eggs"⊢ k.toFun (h.toFun x) = idB.toFun x have h_eval : h x = "Mary" := ⊢ k.toFun ∘ h.toFun = idB.toFun All goals completed! 🐙
have k_eval : k "Mary" = "coffee" := ⊢ k.toFun ∘ h.toFun = idB.toFun All goals completed! 🐙
have idB_eval : idB x = "coffee" := ⊢ k.toFun ∘ h.toFun = idB.toFun All goals completed! 🐙
All goals completed! 🐙
There are 12 such pairs: h(\mathit{eggs}) can take any one of three distinct values in A, leaving h(\mathit{coffee}) to take one of the two remaining values, which together gives {3 \times 2 = 6} combinations; and for each combination, k can map the element in A that is not in the image of h to either \mathit{eggs} or \mathit{coffee}.
1. Guide
A category consists of the DATA:
(1) OBJECTS
(2) MAPS
(3) For each map f, one object as DOMAIN of f and one object as CODOMAIN of f
(4) For each object A an IDENTITY MAP, which has domain A and codomain A
(5) For each pair of maps {A \xrightarrow{f} B \xrightarrow{g} C}, a COMPOSITE MAP map {A \xrightarrow{g \;\mathrm{following}\; f} C}
satisfying the following RULES:
(i) IDENTITY LAWS: If {A \xrightarrow{f} B}, then {1_B \circ f = f} and {f \circ 1_A = f}
(ii) ASSOCIATIVE LAW: If {A \xrightarrow{f} B \xrightarrow{g} C \xrightarrow{h} D}, then {(h \circ g) \circ f = h \circ (g \circ f)}
We print the mathlib definition of Category below for reference.
#print Category