Functions
Analysis I, Section 3.3: Functions
I have attempted to make the translation as faithful a paraphrasing as possible of the original text. When there is a choice between a more idiomatic Lean solution and a more faithful translation, I have generally chosen the latter. In particular, there will be places where the Lean code could be "golfed" to be more elegant and idiomatic, but I have consciously avoided doing so.
Main constructions and results of this section:
-
A notion of function
Function X Ybetween two setsX,Yin the set theory of Section 3.1 -
Various relations with the Mathlib notion of a function
X → Ybetween two typesX,Y. (Note from Section 3.1 that everySetXcan also be viewed as a subtype{x : Object // x ∈ X }ofObject.) -
Basic function properties and operations, such as composition, one-to-one and onto functions, and inverses.
In the rest of the book we will deprecate the Chapter 3 version of a function, and work with the
Mathlib notion of a function instead. Even within this section, we will switch to the Mathlib
formalism for some of the examples involving number systems such as ℤ or ℝ that have not been
implemented in the Chapter 3 framework.
We will work here with the version Nat of the natural numbers internal to the Chapter 3 set
theory, though usually we will use coercions to then immediately translate to the Mathlib
natural numbers ℕ.
Tips from past users
Users of the companion who have completed the exercises in this section are welcome to send their tips for future users in this section as PRs.
-
(Add tip here)
namespace Chapter3export SetTheory (Set Object)variable [SetTheory]
Definition 3.3.1. Function X Y is the structure of functions from X to Y.
Analogous to the Mathlib type X → Y.
@[ext]
structure Function (X Y: Set) where
P : X → Y → Prop
unique : ∀ x: X, ∃! y: Y, P x y
Converting a Chapter 3 function to a Mathlib function .
The Chapter 3 definition of a function was nonconstructive, so we have to use the
axiom of choice here.
noncomputable def Function.to_fn {X Y: Set} (f: Function X Y) : X → Y :=
fun x ↦ (f.unique x).choosenoncomputable instance Function.inst_coefn (X Y: Set) : CoeFun (Function X Y) (fun _ ↦ X → Y) where
coe := Function.to_fntheorem Function.to_fn_eval {X Y: Set} (f: Function X Y) (x:X) : f.to_fn x = f x := rfl
Converting a Mathlib function to a Chapter 3 Function
abbrev Function.mk_fn {X Y: Set} (f: X → Y) : Function X Y :=
Function.mk (fun x y ↦ y = f x) (inst✝:SetTheoryX:SetY:Setf:X.toSubtype → Y.toSubtype⊢ ∀ (x : X.toSubtype), ∃! y, (fun x y => y = f x) x y All goals completed! 🐙)Definition 3.3.1
theorem Function.eval {X Y: Set} (f: Function X Y) (x: X) (y: Y) : y = f x ↔ f.P x y := inst✝:SetTheoryX:SetY:Setf:Function X Yx:X.toSubtypey:Y.toSubtype⊢ y = f.to_fn x ↔ f.P x y
All goals completed! 🐙@[simp]
theorem Function.eval_of {X Y: Set} (f: X → Y) (x:X) : (Function.mk_fn f) x = f x := inst✝:SetTheoryX:SetY:Setf:X.toSubtype → Y.toSubtypex:X.toSubtype⊢ (mk_fn f).to_fn x = f x
inst✝:SetTheoryX:SetY:Setf:X.toSubtype → Y.toSubtypex:X.toSubtype⊢ f x = (mk_fn f).to_fn x; All goals completed! 🐙
theorem SetTheory.Set.P_3_3_3a_existsUnique (x: Nat) : ∃! y: Nat, P_3_3_3a x y := inst✝:SetTheoryx:Nat.toSubtype⊢ ∃! y, P_3_3_3a x y
inst✝:SetTheoryx:Nat.toSubtype⊢ P_3_3_3a x ↑(nat_equiv.symm x + 1)inst✝:SetTheoryx:Nat.toSubtype⊢ ∀ (y : Nat.toSubtype), P_3_3_3a x y → y = ↑(nat_equiv.symm x + 1)
inst✝:SetTheoryx:Nat.toSubtype⊢ P_3_3_3a x ↑(nat_equiv.symm x + 1) All goals completed! 🐙
inst✝:SetTheoryx:Nat.toSubtypey:Nat.toSubtypeh:P_3_3_3a x y⊢ y = ↑(nat_equiv.symm x + 1)
All goals completed! 🐙abbrev SetTheory.Set.f_3_3_3a : Function Nat Nat := Function.mk P_3_3_3a P_3_3_3a_existsUniquetheorem SetTheory.Set.f_3_3_3a_eval (x y: Nat) : y = f_3_3_3a x ↔ (y:ℕ) = (x+1:ℕ) :=
Function.eval _ _ _theorem SetTheory.Set.f_3_3_3a_eval' (n: ℕ) : f_3_3_3a (n:Nat) = (n+1:ℕ) := inst✝:SetTheoryn:ℕ⊢ f_3_3_3a.to_fn ↑n = ↑(n + 1)
inst✝:SetTheoryn:ℕ⊢ ↑(n + 1) = f_3_3_3a.to_fn ↑n
All goals completed! 🐙theorem SetTheory.Set.f_3_3_3a_eval'' : f_3_3_3a 4 = 5 := f_3_3_3a_eval' 4theorem SetTheory.Set.f_3_3_3a_eval''' (n:ℕ) : f_3_3_3a (2*n+3: ℕ) = (2*n+4:ℕ) := inst✝:SetTheoryn:ℕ⊢ f_3_3_3a.to_fn ↑(2 * n + 3) = ↑(2 * n + 4)
All goals completed! 🐙abbrev SetTheory.Set.P_3_3_3b : Nat → Nat → Prop := fun x y ↦ (y+1:ℕ) = (x:ℕ)theorem SetTheory.Set.not_P_3_3_3b_existsUnique : ¬ ∀ x, ∃! y: Nat, P_3_3_3b x y := inst✝:SetTheory⊢ ¬∀ (x : Nat.toSubtype), ∃! y, P_3_3_3b x y
inst✝:SetTheoryh:∀ (x : Nat.toSubtype), ∃! y, P_3_3_3b x y⊢ False
inst✝:SetTheoryh:∀ (x : Nat.toSubtype), ∃! y, P_3_3_3b x yn:Nat.toSubtypehn:P_3_3_3b 0 na✝:∀ (y : Nat.toSubtype), (fun y => P_3_3_3b 0 y) y → y = n⊢ False
have : ((0:Nat):ℕ) = 0 := inst✝:SetTheory⊢ ¬∀ (x : Nat.toSubtype), ∃! y, P_3_3_3b x y All goals completed! 🐙
All goals completed! 🐙abbrev SetTheory.Set.P_3_3_3c : (Nat \ {(0:Object)}: Set) → Nat → Prop :=
fun x y ↦ ((y+1:ℕ):Object) = xtheorem SetTheory.Set.P_3_3_3c_existsUnique (x: (Nat \ {(0:Object)}: Set)) :
∃! y: Nat, P_3_3_3c x y := inst✝:SetTheoryx:(Nat \ {0}).toSubtype⊢ ∃! y, P_3_3_3c x y
-- Some technical unpacking here due to the subtle distinctions between the `Object` type,
-- sets converted to subtypes of `Object`, and subsets of those sets.
inst✝:SetTheoryx:Objecthx:x ∈ Nat \ {0}⊢ ∃! y, P_3_3_3c ⟨x, hx⟩ y; inst✝:SetTheoryx:Objecthx✝:x ∈ Nat \ {0}hx:x ∈ Nat ∧ ¬x = 0⊢ ∃! y, P_3_3_3c ⟨x, hx✝⟩ y; inst✝:SetTheoryx:Objecthx:x ∈ Nat \ {0}hx1:x ∈ Nathx2:¬x = 0⊢ ∃! y, P_3_3_3c ⟨x, hx⟩ y
inst✝:SetTheoryx:Objecthx:x ∈ Nat \ {0}hx1:x ∈ Nathx2:¬x = 0n:ℕ := Chapter3.SetTheory.Set.nat_equiv.symm ⟨_fvar.50161, _fvar.50449⟩⊢ ∃! y, P_3_3_3c ⟨x, hx⟩ y
have : x = (n:Nat) := inst✝:SetTheoryx:(Nat \ {0}).toSubtype⊢ ∃! y, P_3_3_3c x y All goals completed! 🐙
inst✝:SetTheoryx:Objecthx:x ∈ Nat \ {0}hx1:x ∈ Natn:ℕ := Chapter3.SetTheory.Set.nat_equiv.symm ⟨_fvar.50161, _fvar.50449⟩this:_fvar.50161 = ↑↑_fvar.50593 := ?_mvar.51000hx2:¬n = 0⊢ ∃! y, nat_equiv.symm y + 1 = n
replace hx2 : n = (n-1) + 1 := inst✝:SetTheoryx:(Nat \ {0}).toSubtype⊢ ∃! y, P_3_3_3c x y All goals completed! 🐙
inst✝:SetTheoryx:Objecthx:x ∈ Nat \ {0}hx1:x ∈ Natn:ℕ := Chapter3.SetTheory.Set.nat_equiv.symm ⟨_fvar.50161, _fvar.50449⟩this:_fvar.50161 = ↑↑_fvar.50593 := ?_mvar.51000hx2:_fvar.50593 = _fvar.50593 - 1 + 1 := ?_mvar.59231⊢ nat_equiv.symm ↑(n - 1) + 1 = ninst✝:SetTheoryx:Objecthx:x ∈ Nat \ {0}hx1:x ∈ Natn:ℕ := Chapter3.SetTheory.Set.nat_equiv.symm ⟨_fvar.50161, _fvar.50449⟩this:_fvar.50161 = ↑↑_fvar.50593 := ?_mvar.51000hx2:_fvar.50593 = _fvar.50593 - 1 + 1 := ?_mvar.59231⊢ ∀ (y : Nat.toSubtype), nat_equiv.symm y + 1 = n → y = ↑(n - 1)
inst✝:SetTheoryx:Objecthx:x ∈ Nat \ {0}hx1:x ∈ Natn:ℕ := Chapter3.SetTheory.Set.nat_equiv.symm ⟨_fvar.50161, _fvar.50449⟩this:_fvar.50161 = ↑↑_fvar.50593 := ?_mvar.51000hx2:_fvar.50593 = _fvar.50593 - 1 + 1 := ?_mvar.59231⊢ nat_equiv.symm ↑(n - 1) + 1 = n All goals completed! 🐙
inst✝:SetTheoryx:Objecthx:x ∈ Nat \ {0}hx1:x ∈ Natn:ℕ := Chapter3.SetTheory.Set.nat_equiv.symm ⟨_fvar.50161, _fvar.50449⟩this:_fvar.50161 = ↑↑_fvar.50593 := ?_mvar.51000hx2:_fvar.50593 = _fvar.50593 - 1 + 1 := ?_mvar.59231y:Nat.toSubtypehy:nat_equiv.symm y + 1 = n⊢ y = ↑(n - 1); All goals completed! 🐙abbrev SetTheory.Set.f_3_3_3c : Function (Nat \ {(0:Object)}: Set) Nat :=
Function.mk P_3_3_3c P_3_3_3c_existsUniquetheorem SetTheory.Set.f_3_3_3c_eval (x: (Nat \ {(0:Object)}: Set)) (y: Nat) :
y = f_3_3_3c x ↔ ((y+1:ℕ):Object) = x := Function.eval _ _ _
Create a version of a non-zero n inside Nat \ {0} for any natural number n.
abbrev SetTheory.Set.coe_nonzero (n:ℕ) (h: n ≠ 0): (Nat \ {(0:Object)}: Set) :=
⟨((n:ℕ):Object), inst✝:SetTheoryn:ℕh:n ≠ 0⊢ ↑n ∈ Nat \ {0}
inst✝:SetTheoryn:ℕh:n ≠ 0⊢ ↑n ∈ Nat
inst✝:SetTheoryn:ℕh:n ≠ 0⊢ ↑↑n ∈ Nat
All goals completed! 🐙
⟩theorem SetTheory.Set.f_3_3_3c_eval' (n: ℕ) : f_3_3_3c (coe_nonzero (n+1) (inst✝:SetTheoryn:ℕ⊢ n + 1 ≠ 0 All goals completed! 🐙)) = n := inst✝:SetTheoryn:ℕ⊢ f_3_3_3c.to_fn (coe_nonzero (n + 1) ⋯) = ↑n
inst✝:SetTheoryn:ℕ⊢ ↑n = f_3_3_3c.to_fn (coe_nonzero (n + 1) ⋯); All goals completed! 🐙theorem SetTheory.Set.f_3_3_3c_eval'' : f_3_3_3c (coe_nonzero 4 (inst✝:SetTheory⊢ 4 ≠ 0 All goals completed! 🐙)) = 3 := inst✝:SetTheory⊢ f_3_3_3c.to_fn (coe_nonzero 4 ⋯) = 3
All goals completed! 🐙theorem SetTheory.Set.f_3_3_3c_eval''' (n:ℕ) :
f_3_3_3c (coe_nonzero (2*n+3) (inst✝:SetTheoryn:ℕ⊢ 2 * n + 3 ≠ 0 All goals completed! 🐙)) = (2*n+2:ℕ) := inst✝:SetTheoryn:ℕ⊢ f_3_3_3c.to_fn (coe_nonzero (2 * n + 3) ⋯) = ↑(2 * n + 2) All goals completed! 🐙
Example 3.3.4 is a little tricky to replicate with the current formalism as the real numbers
have not been constructed yet. Instead, I offer some Mathlib counterparts, using the
Mathlib API for NNReal and ℝ.
example : ¬ ∃ f: ℝ → ℝ, ∀ x y, y = f x ↔ y^2 = x := inst✝:SetTheory⊢ ¬∃ f, ∀ (x y : ℝ), y = f x ↔ y ^ 2 = x
inst✝:SetTheoryh:∃ f, ∀ (x y : ℝ), y = f x ↔ y ^ 2 = x⊢ False
inst✝:SetTheoryf:ℝ → ℝhf:∀ (x y : ℝ), y = f x ↔ y ^ 2 = x⊢ False; inst✝:SetTheoryf:ℝ → ℝhf:∀ (x y : ℝ), y = f x ↔ y ^ 2 = xy:ℝ := @_fvar.81408 (-1)⊢ False
have h1 := (hf _ y).mp (inst✝:SetTheoryf:ℝ → ℝhf:∀ (x y : ℝ), y = f x ↔ y ^ 2 = xy:ℝ := @_fvar.81408 (-1)⊢ y = f ?m.49 All goals completed! 🐙)
inst✝:SetTheoryf:ℝ → ℝhf:∀ (x y : ℝ), y = f x ↔ y ^ 2 = xy:ℝ := @_fvar.81408 (-1)h1:?_mvar.81525 := failed to pretty print expression (use 'set_option pp.rawOnError true' for raw representation)h2:?_mvar.81542 := sq_nonneg _fvar.81471⊢ False
All goals completed! 🐙example : ¬ ∃ f: NNReal → ℝ, ∀ x y, y = f x ↔ y^2 = x := inst✝:SetTheory⊢ ¬∃ f, ∀ (x : NNReal) (y : ℝ), y = f x ↔ y ^ 2 = ↑x
inst✝:SetTheoryh:∃ f, ∀ (x : NNReal) (y : ℝ), y = f x ↔ y ^ 2 = ↑x⊢ False
inst✝:SetTheoryf:NNReal → ℝhf:∀ (x : NNReal) (y : ℝ), y = f x ↔ y ^ 2 = ↑x⊢ False; inst✝:SetTheoryf:NNReal → ℝhf:∀ (y : ℝ), y = f 4 ↔ y ^ 2 = ↑4⊢ False; inst✝:SetTheoryf:NNReal → ℝy:ℝ := @_fvar.82895 4hf:∀ (y_1 : ℝ), y_1 = y ↔ y_1 ^ 2 = ↑4⊢ False
have hy := (hf y).mp (inst✝:SetTheoryf:NNReal → ℝy:ℝ := @_fvar.82895 4hf:∀ (y_1 : ℝ), y_1 = y ↔ y_1 ^ 2 = ↑4⊢ y = y All goals completed! 🐙)
have h1 : 2 = y := (hf 2).mpr (inst✝:SetTheoryf:NNReal → ℝy:ℝ := @_fvar.82895 4hf:∀ (y_1 : ℝ), y_1 = y ↔ y_1 ^ 2 = ↑4hy:_fvar.83076 ^ 2 = ↑4 := failed to pretty print expression (use 'set_option pp.rawOnError true' for raw representation)⊢ 2 ^ 2 = ↑4 All goals completed! 🐙)
have h2 : -2 = y := (hf (-2)).mpr (inst✝:SetTheoryf:NNReal → ℝy:ℝ := @_fvar.82895 4hf:∀ (y_1 : ℝ), y_1 = y ↔ y_1 ^ 2 = ↑4hy:_fvar.83076 ^ 2 = ↑4 := failed to pretty print expression (use 'set_option pp.rawOnError true' for raw representation)h1:2 = _fvar.83076 := failed to pretty print expression (use 'set_option pp.rawOnError true' for raw representation)⊢ (-2) ^ 2 = ↑4 All goals completed! 🐙)
All goals completed! 🐙example : ∃ f: NNReal → NNReal, ∀ x y, y = f x ↔ y^2 = x := inst✝:SetTheory⊢ ∃ f, ∀ (x y : NNReal), y = f x ↔ y ^ 2 = x
inst✝:SetTheory⊢ ∀ (x y : NNReal), y = NNReal.sqrt x ↔ y ^ 2 = x; inst✝:SetTheoryx:NNRealy:NNReal⊢ y = NNReal.sqrt x ↔ y ^ 2 = x
inst✝:SetTheoryx:NNRealy:NNReal⊢ y = NNReal.sqrt x → y ^ 2 = xinst✝:SetTheoryx:NNRealy:NNReal⊢ y ^ 2 = x → y = NNReal.sqrt x inst✝:SetTheoryx:NNRealy:NNReal⊢ y = NNReal.sqrt x → y ^ 2 = xinst✝:SetTheoryx:NNRealy:NNReal⊢ y ^ 2 = x → y = NNReal.sqrt x inst✝:SetTheoryx:NNRealy:NNRealh:y ^ 2 = x⊢ y = NNReal.sqrt x
inst✝:SetTheoryx:NNRealy:NNRealh:y = NNReal.sqrt x⊢ y ^ 2 = x All goals completed! 🐙
inst✝:SetTheoryx:NNRealy:NNRealh:y ^ 2 = x⊢ y = NNReal.sqrt x All goals completed! 🐙
Example 3.3.5. The unused variable _x is underscored to avoid triggering a linter.
abbrev SetTheory.Set.P_3_3_5 : Nat → Nat → Prop := fun _x y ↦ y = 7theorem SetTheory.Set.P_3_3_5_existsUnique (x: Nat) : ∃! y: Nat, P_3_3_5 x y := inst✝:SetTheoryx:Nat.toSubtype⊢ ∃! y, P_3_3_5 x y
inst✝:SetTheoryx:Nat.toSubtype⊢ P_3_3_5 x 7inst✝:SetTheoryx:Nat.toSubtype⊢ ∀ (y : Nat.toSubtype), P_3_3_5 x y → y = 7 inst✝:SetTheoryx:Nat.toSubtype⊢ P_3_3_5 x 7inst✝:SetTheoryx:Nat.toSubtype⊢ ∀ (y : Nat.toSubtype), P_3_3_5 x y → y = 7 All goals completed! 🐙abbrev SetTheory.Set.f_3_3_5 : Function Nat Nat := Function.mk P_3_3_5 P_3_3_5_existsUniquetheorem SetTheory.Set.f_3_3_5_eval (x: Nat) : f_3_3_5 x = 7 := inst✝:SetTheoryx:Nat.toSubtype⊢ f_3_3_5.to_fn x = 7
inst✝:SetTheoryx:Nat.toSubtype⊢ 7 = f_3_3_5.to_fn x; All goals completed! 🐙Definition 3.3.8 (Equality of functions)
theorem Function.eq_iff {X Y: Set} (f g: Function X Y) : f = g ↔ ∀ x: X, f x = g x := inst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Y⊢ f = g ↔ ∀ (x : X.toSubtype), f.to_fn x = g.to_fn x
inst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Y⊢ f = g → ∀ (x : X.toSubtype), f.to_fn x = g.to_fn xinst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Y⊢ (∀ (x : X.toSubtype), f.to_fn x = g.to_fn x) → f = g inst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Y⊢ f = g → ∀ (x : X.toSubtype), f.to_fn x = g.to_fn xinst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Y⊢ (∀ (x : X.toSubtype), f.to_fn x = g.to_fn x) → f = g inst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Yh:∀ (x : X.toSubtype), f.to_fn x = g.to_fn x⊢ f = g
inst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Yh:f = g⊢ ∀ (x : X.toSubtype), f.to_fn x = g.to_fn x All goals completed! 🐙
inst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Yh:∀ (x : X.toSubtype), f.to_fn x = g.to_fn xx:X.toSubtypey:Y.toSubtype⊢ f.P x y ↔ g.P x y; inst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Yh:∀ (x : X.toSubtype), f.to_fn x = g.to_fn xx:X.toSubtypey:Y.toSubtype⊢ f.P x y → g.P x yinst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Yh:∀ (x : X.toSubtype), f.to_fn x = g.to_fn xx:X.toSubtypey:Y.toSubtype⊢ g.P x y → f.P x y inst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Yh:∀ (x : X.toSubtype), f.to_fn x = g.to_fn xx:X.toSubtypey:Y.toSubtype⊢ f.P x y → g.P x yinst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Yh:∀ (x : X.toSubtype), f.to_fn x = g.to_fn xx:X.toSubtypey:Y.toSubtype⊢ g.P x y → f.P x y inst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Yh:∀ (x : X.toSubtype), f.to_fn x = g.to_fn xx:X.toSubtypey:Y.toSubtypea✝:g.P x y⊢ f.P x y
inst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Yh:∀ (x : X.toSubtype), f.to_fn x = g.to_fn xx:X.toSubtypey:Y.toSubtypea✝:f.P x y⊢ g.P x y rwa [←Function.eval, ←h x, Function.evalinst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Yh:∀ (x : X.toSubtype), f.to_fn x = g.to_fn xx:X.toSubtypey:Y.toSubtypea✝:f.P x y⊢ f.P x y
rwa [←Function.eval, h x, Function.evalinst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Yh:∀ (x : X.toSubtype), f.to_fn x = g.to_fn xx:X.toSubtypey:Y.toSubtypea✝:g.P x y⊢ g.P x yExample 3.3.10 (simplified). The second part of the example is tricky to replicate in this formalism, so a Mathlib substitute is offered instead.
abbrev SetTheory.Set.f_3_3_10a : Function Nat Nat := Function.mk_fn (fun x ↦ (x^2 + 2*x + 1:ℕ))abbrev SetTheory.Set.f_3_3_10b : Function Nat Nat := Function.mk_fn (fun x ↦ ((x+1)^2:ℕ))theorem SetTheory.Set.f_3_3_10_eq : f_3_3_10a = f_3_3_10b := inst✝:SetTheory⊢ f_3_3_10a = f_3_3_10b
inst✝:SetTheory⊢ ∀ (x : Nat.toSubtype), ↑(nat_equiv.symm x ^ 2 + 2 * nat_equiv.symm x + 1) = ↑((nat_equiv.symm x + 1) ^ 2)
inst✝:SetTheoryx✝:Nat.toSubtype⊢ ↑(nat_equiv.symm x✝ ^ 2 + 2 * nat_equiv.symm x✝ + 1) = ↑((nat_equiv.symm x✝ + 1) ^ 2); inst✝:SetTheoryx✝:Nat.toSubtype⊢ nat_equiv.symm x✝ ^ 2 + 2 * nat_equiv.symm x✝ + 1 = (nat_equiv.symm x✝ + 1) ^ 2; All goals completed! 🐙example : (fun x:NNReal ↦ (x:ℝ)) = (fun x:NNReal ↦ |(x:ℝ)|) := inst✝:SetTheory⊢ (fun x => ↑x) = fun x => |↑x|
All goals completed! 🐙example : (fun x:ℝ ↦ (x:ℝ)) ≠ (fun x:ℝ ↦ |(x:ℝ)|) := inst✝:SetTheory⊢ (fun x => x) ≠ fun x => |x|
inst✝:SetTheoryh:(fun x => x) = fun x => |x|⊢ False
inst✝:SetTheoryh:(fun x => x) = fun x => |x|a:?_mvar.91839 := (fun x => x) (-1)⊢ False
inst✝:SetTheoryh:(fun x => x) = fun x => |x|a:?_mvar.91839 := (fun x => x) (-1)b:?_mvar.91906 := (fun x => |x|) (-1)⊢ False
have hab : a = b := inst✝:SetTheory⊢ (fun x => x) ≠ fun x => |x| inst✝:SetTheoryh:(fun x => x) = fun x => |x|a:?_mvar.91839 := (fun x => x) (-1)b:?_mvar.91906 := (fun x => |x|) (-1)⊢ (fun x => x) (-1) = b; All goals completed! 🐙
All goals completed! 🐙Example 3.3.11
abbrev SetTheory.Set.f_3_3_11 (X:Set) : Function (∅:Set) X :=
Function.mk (fun _ _ ↦ True) (inst✝:SetTheoryX:Set⊢ ∀ (x : ∅.toSubtype), ∃! y, (fun x x => True) x y inst✝:SetTheoryX:Setx:Objecthx:x ∈ ∅⊢ ∃! y, (fun x x => True) ⟨x, hx⟩ y; All goals completed! 🐙)theorem SetTheory.Set.empty_function_unique {X: Set} (f g: Function (∅:Set) X) : f = g := inst✝:SetTheoryX:Setf:Function ∅ Xg:Function ∅ X⊢ f = g All goals completed! 🐙Definition 3.3.13 (Composition)
noncomputable abbrev Function.comp {X Y Z: Set} (g: Function Y Z) (f: Function X Y) :
Function X Z :=
Function.mk_fn (fun x ↦ g (f x))-- `∘` is already taken in Mathlib for the composition of Mathlib functions,
-- so we use `○` here instead to avoid ambiguity.
infix:90 "○" => Function.comptheorem Function.comp_eval {X Y Z: Set} (g: Function Y Z) (f: Function X Y) (x: X) :
(g ○ f) x = g (f x) := Function.eval_of _ _Compatibility with Mathlib's composition operation.
theorem Function.comp_eq_comp {X Y Z: Set} (g: Function Y Z) (f: Function X Y) :
(g ○ f).to_fn = g.to_fn ∘ f.to_fn := inst✝:SetTheoryX:SetY:SetZ:Setg:Function Y Zf:Function X Y⊢ (g○f).to_fn = g.to_fn ∘ f.to_fn
inst✝:SetTheoryX:SetY:SetZ:Setg:Function Y Zf:Function X Yx✝:X.toSubtype⊢ ↑((g○f).to_fn x✝) = ↑((g.to_fn ∘ f.to_fn) x✝); All goals completed! 🐙abbrev SetTheory.Set.g_3_3_14 : Function Nat Nat := Function.mk_fn (fun x ↦ (x+3:ℕ))theorem SetTheory.Set.g_circ_f_3_3_14 :
g_3_3_14 ○ f_3_3_14 = Function.mk_fn (fun x ↦ ((2*(x:ℕ)+3:ℕ):Nat)) := inst✝:SetTheory⊢ g_3_3_14○f_3_3_14 = Function.mk_fn fun x => ↑(2 * nat_equiv.symm x + 3)
All goals completed! 🐙theorem SetTheory.Set.f_circ_g_3_3_14 :
f_3_3_14 ○ g_3_3_14 = Function.mk_fn (fun x ↦ ((2*(x:ℕ)+6:ℕ):Nat)) := inst✝:SetTheory⊢ f_3_3_14○g_3_3_14 = Function.mk_fn fun x => ↑(2 * nat_equiv.symm x + 6)
inst✝:SetTheory⊢ ∀ (a : Object) (b : a ∈ Nat), 2 * (nat_equiv.symm ⟨a, b⟩ + 3) = 2 * nat_equiv.symm ⟨a, b⟩ + 6
inst✝:SetTheorya✝:Objectb✝:a✝ ∈ Nat⊢ 2 * (nat_equiv.symm ⟨a✝, b✝⟩ + 3) = 2 * nat_equiv.symm ⟨a✝, b✝⟩ + 6; All goals completed! 🐙Lemma 3.3.15 (Composition is associative)
theorem SetTheory.Set.comp_assoc {W X Y Z: Set} (h: Function Y Z) (g: Function X Y)
(f: Function W X) :
h ○ (g ○ f) = (h ○ g) ○ f := inst✝:SetTheoryW:SetX:SetY:SetZ:Seth:Function Y Zg:Function X Yf:Function W X⊢ h○(g○f) = (h○g)○f
All goals completed! 🐙abbrev Function.one_to_one {X Y: Set} (f: Function X Y) : Prop := ∀ x x': X, x ≠ x' → f x ≠ f x'theorem Function.one_to_one_iff {X Y: Set} (f: Function X Y) :
f.one_to_one ↔ ∀ x x': X, f x = f x' → x = x' := inst✝:SetTheoryX:SetY:Setf:Function X Y⊢ f.one_to_one ↔ ∀ (x x' : X.toSubtype), f.to_fn x = f.to_fn x' → x = x'
inst✝:SetTheoryX:SetY:Setf:Function X Yx:X.toSubtypehx:X.toSubtype⊢ x ≠ hx → f.to_fn x ≠ f.to_fn hx ↔ f.to_fn x = f.to_fn hx → x = hx; All goals completed! 🐙
Compatibility with Mathlib's Function.Injective. You may wish to use the unfold tactic to
understand Mathlib concepts such as Function.Injective.
theorem Function.one_to_one_iff' {X Y: Set} (f: Function X Y) :
f.one_to_one ↔ Function.Injective f.to_fn := inst✝:SetTheoryX:SetY:Setf:Function X Y⊢ f.one_to_one ↔ Function.Injective f.to_fn
All goals completed! 🐙Example 3.3.18. One half of the example requires the integers, and so is expressed using Mathlib functions instead of Chapter 3 functions.
theorem SetTheory.Set.f_3_3_18_one_to_one :
(Function.mk_fn (fun (n:Nat) ↦ ((n^2:ℕ):Nat))).one_to_one := inst✝:SetTheory⊢ (Function.mk_fn fun n => ↑(nat_equiv.symm n ^ 2)).one_to_one
inst✝:SetTheory⊢ ∀ (x x' : Nat.toSubtype),
(Function.mk_fn fun n => ↑(nat_equiv.symm n ^ 2)).to_fn x =
(Function.mk_fn fun n => ↑(nat_equiv.symm n ^ 2)).to_fn x' →
x = x'
inst✝:SetTheoryx✝:Nat.toSubtypex'✝:Nat.toSubtypeh:(Function.mk_fn fun n => ↑(nat_equiv.symm n ^ 2)).to_fn x✝ = (Function.mk_fn fun n => ↑(nat_equiv.symm n ^ 2)).to_fn x'✝⊢ x✝ = x'✝
All goals completed! 🐙example : ¬ Function.Injective (fun (n:ℤ) ↦ n^2) := inst✝:SetTheory⊢ ¬Function.Injective fun n => n ^ 2
inst✝:SetTheoryh:Function.Injective fun n => n ^ 2⊢ False
have h1 : (fun n ↦ n ^ 2) 1 = (1:ℤ) := inst✝:SetTheory⊢ ¬Function.Injective fun n => n ^ 2 All goals completed! 🐙
have h2 : (fun n ↦ n ^ 2) (-1) = (1:ℤ) := inst✝:SetTheory⊢ ¬Function.Injective fun n => n ^ 2 All goals completed! 🐙
inst✝:SetTheoryh:Function.Injective fun n => n ^ 2h1:(fun n => n ^ 2) 1 = 1 := ?_mvar.127345h2:(fun n => n ^ 2) (-1) = (fun n => n ^ 2) 1⊢ False
inst✝:SetTheoryh1:(fun n => n ^ 2) 1 = 1 := ?_mvar.127345h2:(fun n => n ^ 2) (-1) = (fun n => n ^ 2) 1h:-1 = 1⊢ False
All goals completed! 🐙example : Function.Injective (fun (n:ℕ) ↦ n^2) := inst✝:SetTheory⊢ Function.Injective fun n => n ^ 2
inst✝:SetTheorya₁✝:ℕa₂✝:ℕa✝:(fun n => n ^ 2) a₁✝ = (fun n => n ^ 2) a₂✝⊢ a₁✝ = a₂✝; rwa [← pow_left_inj₀ (inst✝:SetTheorya₁✝:ℕa₂✝:ℕa✝:(fun n => n ^ 2) a₁✝ = (fun n => n ^ 2) a₂✝⊢ 0 ≤ a₁✝ All goals completed! 🐙) (inst✝:SetTheorya₁✝:ℕa₂✝:ℕa✝:(fun n => n ^ 2) a₁✝ = (fun n => n ^ 2) a₂✝⊢ 0 ≤ a₂✝ All goals completed! 🐙) (show 2 ≠ 0 inst✝:SetTheory⊢ Function.Injective fun n => n ^ 2 All goals completed! 🐙)inst✝:SetTheorya₁✝:ℕa₂✝:ℕa✝:(fun n => n ^ 2) a₁✝ = (fun n => n ^ 2) a₂✝⊢ a₁✝ ^ 2 = a₂✝ ^ 2Remark 3.3.19
theorem SetTheory.Set.two_to_one {X Y: Set} {f: Function X Y} (h: ¬ f.one_to_one) :
∃ x x': X, x ≠ x' ∧ f x = f x' := inst✝:SetTheoryX:SetY:Setf:Function X Yh:¬f.one_to_one⊢ ∃ x x', x ≠ x' ∧ f.to_fn x = f.to_fn x'
inst✝:SetTheoryX:SetY:Setf:Function X Yh:¬∀ (x x' : X.toSubtype), x ≠ x' → f.to_fn x ≠ f.to_fn x'⊢ ∃ x x', x ≠ x' ∧ f.to_fn x = f.to_fn x'; All goals completed! 🐙Definition 3.3.20 (Onto functions)
abbrev Function.onto {X Y: Set} (f: Function X Y) : Prop := ∀ y: Y, ∃ x: X, f x = yCompatibility with Mathlib's Function.Surjective
theorem Function.onto_iff {X Y: Set} (f: Function X Y) : f.onto ↔ Function.Surjective f.to_fn := inst✝:SetTheoryX:SetY:Setf:Function X Y⊢ f.onto ↔ Function.Surjective f.to_fn All goals completed! 🐙Example 3.3.21 (using Mathlib)
example : ¬ Function.Surjective (fun (n:ℤ) ↦ n^2) := inst✝:SetTheory⊢ ¬Function.Surjective fun n => n ^ 2
inst✝:SetTheory⊢ ¬∀ (b : ℤ), ∃ a, (fun n => n ^ 2) a = b; inst✝:SetTheory⊢ ∃ b, ∀ (a : ℤ), a ^ 2 ≠ b
inst✝:SetTheory⊢ ∀ (a : ℤ), a ^ 2 ≠ -1; inst✝:SetTheorya:ℤ⊢ a ^ 2 ≠ -1
All goals completed! 🐙abbrev A_3_3_21 := { m:ℤ // ∃ n:ℤ, m = n^2 }example : Function.Surjective (fun (n:ℤ) ↦ ⟨ n^2, inst✝:SetTheoryn:ℤ⊢ ∃ n_1, n ^ 2 = n_1 ^ 2 All goals completed! 🐙 ⟩ : ℤ → A_3_3_21) := inst✝:SetTheory⊢ Function.Surjective fun n => ⟨n ^ 2, ⋯⟩
inst✝:SetTheoryb:ℤa:ℤha:b = a ^ 2⊢ ∃ a_1, (fun n => ⟨n ^ 2, ⋯⟩) a_1 = ⟨b, ⋯⟩; inst✝:SetTheoryb:ℤa:ℤha:b = a ^ 2⊢ (fun n => ⟨n ^ 2, ⋯⟩) a = ⟨b, ⋯⟩
All goals completed! 🐙Definition 3.3.23 (Bijective functions)
abbrev Function.bijective {X Y: Set} (f: Function X Y) : Prop := f.one_to_one ∧ f.ontoCompatibility with Mathlib's Function.Bijective
theorem Function.bijective_iff {X Y: Set} (f: Function X Y) :
f.bijective ↔ Function.Bijective f.to_fn := inst✝:SetTheoryX:SetY:Setf:Function X Y⊢ f.bijective ↔ Function.Bijective f.to_fn
All goals completed! 🐙Example 3.3.24 (using Mathlib)
abbrev f_3_3_24 : Fin 3 → ({3,4}:_root_.Set ℕ) := fun x ↦ match x with
| 0 => ⟨ 3, inst✝:SetTheoryx:Fin 3⊢ 3 ∈ {3, 4} All goals completed! 🐙 ⟩
| 1 => ⟨ 3, inst✝:SetTheoryx:Fin 3⊢ 3 ∈ {3, 4} All goals completed! 🐙 ⟩
| 2 => ⟨ 4, inst✝:SetTheoryx:Fin 3⊢ 4 ∈ {3, 4} All goals completed! 🐙 ⟩example : ¬ Function.Injective f_3_3_24 := inst✝:SetTheory⊢ ¬Function.Injective f_3_3_24 All goals completed! 🐙example : ¬ Function.Bijective f_3_3_24 := inst✝:SetTheory⊢ ¬Function.Bijective f_3_3_24 All goals completed! 🐙abbrev g_3_3_24 : Fin 2 → ({2,3,4}:_root_.Set ℕ) := fun x ↦ match x with
| 0 => ⟨ 2, inst✝:SetTheoryx:Fin 2⊢ 2 ∈ {2, 3, 4} All goals completed! 🐙 ⟩
| 1 => ⟨ 3, inst✝:SetTheoryx:Fin 2⊢ 3 ∈ {2, 3, 4} All goals completed! 🐙 ⟩example : ¬ Function.Surjective g_3_3_24 := inst✝:SetTheory⊢ ¬Function.Surjective g_3_3_24 All goals completed! 🐙example : ¬ Function.Bijective g_3_3_24 := inst✝:SetTheory⊢ ¬Function.Bijective g_3_3_24 All goals completed! 🐙abbrev h_3_3_24 : Fin 3 → ({3,4,5}:_root_.Set ℕ) := fun x ↦ match x with
| 0 => ⟨ 3, inst✝:SetTheoryx:Fin 3⊢ 3 ∈ {3, 4, 5} All goals completed! 🐙 ⟩
| 1 => ⟨ 4, inst✝:SetTheoryx:Fin 3⊢ 4 ∈ {3, 4, 5} All goals completed! 🐙 ⟩
| 2 => ⟨ 5, inst✝:SetTheoryx:Fin 3⊢ 5 ∈ {3, 4, 5} All goals completed! 🐙 ⟩example : Function.Bijective h_3_3_24 := inst✝:SetTheory⊢ Function.Bijective h_3_3_24 All goals completed! 🐙Example 3.3.25 is formulated using Mathlib rather than the set theory framework here to avoid some tedious technical issues (cf. Exercise 3.3.2)
example : Function.Bijective (fun n ↦ ⟨ n+1, inst✝:SetTheoryn:ℕ⊢ n + 1 ≠ 0 All goals completed! 🐙⟩ : ℕ → { n:ℕ // n ≠ 0 }) := inst✝:SetTheory⊢ Function.Bijective fun n => ⟨n + 1, ⋯⟩
inst✝:SetTheory⊢ Function.Injective fun n => ⟨n + 1, ⋯⟩inst✝:SetTheory⊢ Function.Surjective fun n => ⟨n + 1, ⋯⟩
inst✝:SetTheory⊢ Function.Injective fun n => ⟨n + 1, ⋯⟩ inst✝:SetTheorya₁✝:ℕa₂✝:ℕ⊢ (fun n => ⟨n + 1, ⋯⟩) a₁✝ = (fun n => ⟨n + 1, ⋯⟩) a₂✝ → a₁✝ = a₂✝
inst✝:SetTheorya₁✝:ℕa₂✝:ℕ⊢ a₁✝ + 1 = a₂✝ + 1 → a₁✝ = a₂✝; All goals completed! 🐙
inst✝:SetTheoryx:ℕhx:x ≠ 0⊢ ∃ a, (fun n => ⟨n + 1, ⋯⟩) a = ⟨x, hx⟩; inst✝:SetTheoryx:ℕhx:x ≠ 0⊢ (fun n => ⟨n + 1, ⋯⟩) (x - 1) = ⟨x, hx⟩
inst✝:SetTheoryx:ℕhx:x ≠ 0⊢ x - 1 + 1 = x; All goals completed! 🐙example : ¬ Function.Bijective (fun n ↦ n+1) := inst✝:SetTheory⊢ ¬Function.Bijective fun n => n + 1
suffices h : ¬ Function.Surjective (fun n ↦ n+1) inst✝:SetTheoryh:¬Function.Surjective fun n => n + 1 := ?_mvar.230004⊢ ¬Function.Bijective fun n => n + 1 inst✝:SetTheoryh:¬Function.Surjective fun n => n + 1 := ?_mvar.230004⊢ ¬((Function.Injective fun n => n + 1) ∧ Function.Surjective fun n => n + 1); All goals completed! 🐙
inst✝:SetTheory⊢ ¬∀ (b : ℕ), ∃ a, (fun n => n + 1) a = b; inst✝:SetTheory⊢ ∃ b, ∀ (a : ℕ), a + 1 ≠ b
inst✝:SetTheory⊢ ∀ (a : ℕ), a + 1 ≠ 0; inst✝:SetTheorya✝:ℕ⊢ a✝ + 1 ≠ 0
inst✝:SetTheorya✝:ℕ⊢ 0 ≠ a✝ + 1; All goals completed! 🐙Remark 3.3.27
theorem Function.bijective_incorrect_def :
∃ X Y: Set, ∃ f: Function X Y, (∀ x: X, ∃! y: Y, y = f x) ∧ ¬ f.bijective := inst✝:SetTheory⊢ ∃ X Y f, (∀ (x : X.toSubtype), ∃! y, y = f.to_fn x) ∧ ¬f.bijective
inst✝:SetTheory⊢ ∃ f, (∀ (x : Nat.toSubtype), ∃! y, y = f.to_fn x) ∧ ¬f.bijective
inst✝:SetTheoryf:Chapter3.Function ?_mvar.230839 (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0⊢ ∃ f, (∀ (x : Nat.toSubtype), ∃! y, y = f.to_fn x) ∧ ¬f.bijective; inst✝:SetTheoryf:Chapter3.Function ?_mvar.230839 (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0⊢ (∀ (x : Nat.toSubtype), ∃! y, y = f.to_fn x) ∧ ¬f.bijective
inst✝:SetTheoryf:Chapter3.Function ?_mvar.230839 (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0⊢ ∀ (x : Nat.toSubtype), ∃! y, y = f.to_fn xinst✝:SetTheoryf:Chapter3.Function ?_mvar.230839 (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0⊢ ¬f.bijective
inst✝:SetTheoryf:Chapter3.Function ?_mvar.230839 (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0⊢ ∀ (x : Nat.toSubtype), ∃! y, y = f.to_fn x inst✝:SetTheoryf:Chapter3.Function ?_mvar.230839 (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0x✝:Nat.toSubtype⊢ ∃! y, y = f.to_fn x✝
inst✝:SetTheoryf:Chapter3.Function ?_mvar.230839 (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0x✝:Nat.toSubtype⊢ ∃ x, x = f.to_fn x✝inst✝:SetTheoryf:Chapter3.Function ?_mvar.230839 (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0x✝:Nat.toSubtype⊢ ∀ (y₁ y₂ : Nat.toSubtype), y₁ = f.to_fn x✝ → y₂ = f.to_fn x✝ → y₁ = y₂
inst✝:SetTheoryf:Chapter3.Function ?_mvar.230839 (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0x✝:Nat.toSubtype⊢ ∃ x, x = f.to_fn x✝ inst✝:SetTheoryf:Chapter3.Function ?_mvar.230839 (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0x✝:Nat.toSubtype⊢ 0 = f.to_fn x✝; All goals completed! 🐙
inst✝:SetTheoryf:Chapter3.Function ?_mvar.230839 (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0x✝:Nat.toSubtypey₁✝:Nat.toSubtypey₂✝:Nat.toSubtypea✝¹:y₁✝ = f.to_fn x✝a✝:y₂✝ = f.to_fn x✝⊢ y₁✝ = y₂✝; inst✝:SetTheoryf:Chapter3.Function ?_mvar.230839 (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0x✝:Nat.toSubtypey₁✝:Nat.toSubtypey₂✝:Nat.toSubtypea✝¹:f.P x✝ y₁✝a✝:f.P x✝ y₂✝⊢ y₁✝ = y₂✝; All goals completed! 🐙
inst✝:SetTheoryf:Chapter3.Function ?_mvar.230839 (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0⊢ ¬(f.one_to_one ∧ f.onto)
suffices h : ¬ f.one_to_one inst✝:SetTheoryf:Chapter3.Function (@Chapter3.Nat _fvar.230652) (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0h:¬Chapter3.Function.one_to_one _fvar.230889 := ?_mvar.231550⊢ ¬(f.one_to_one ∧ f.onto) All goals completed! 🐙
inst✝:SetTheoryf:Chapter3.Function ?_mvar.230839 (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0⊢ ¬∀ (x x' : Nat.toSubtype), f.to_fn x = f.to_fn x' → x = x'
inst✝:SetTheoryf:Chapter3.Function ?_mvar.230839 (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0⊢ ∃ x x', f.to_fn x = f.to_fn x' ∧ x ≠ x'; inst✝:SetTheoryf:Chapter3.Function ?_mvar.230839 (@Chapter3.Nat _fvar.230652) := Chapter3.Function.mk_fn fun x => 0⊢ f.to_fn 0 = f.to_fn 1 ∧ 0 ≠ 1; All goals completed! 🐙
We cannot use the notation f⁻¹ for the inverse because in Mathlib's Inv class, the inverse
of f must be exactly of the same type of f, and Function Y X is a different type from
Function X Y.
abbrev Function.inverse {X Y: Set} (f: Function X Y) (h: f.bijective) :
Function Y X :=
Function.mk (fun y x ↦ f x = y) (inst✝:SetTheoryX:SetY:Setf:Function X Yh:f.bijective⊢ ∀ (x : Y.toSubtype), ∃! y, (fun y x => f.to_fn x = y) x y
inst✝:SetTheoryX:SetY:Setf:Function X Yh:f.bijectivex✝:Y.toSubtype⊢ ∃! y, (fun y x => f.to_fn x = y) x✝ y
inst✝:SetTheoryX:SetY:Setf:Function X Yh:f.bijectivex✝:Y.toSubtype⊢ ∃ x, (fun y x => f.to_fn x = y) x✝ xinst✝:SetTheoryX:SetY:Setf:Function X Yh:f.bijectivex✝:Y.toSubtype⊢ ∀ (y₁ y₂ : X.toSubtype), (fun y x => f.to_fn x = y) x✝ y₁ → (fun y x => f.to_fn x = y) x✝ y₂ → y₁ = y₂
inst✝:SetTheoryX:SetY:Setf:Function X Yh:f.bijectivex✝:Y.toSubtype⊢ ∃ x, (fun y x => f.to_fn x = y) x✝ x All goals completed! 🐙
inst✝:SetTheoryX:SetY:Setf:Function X Yh:f.bijectivex✝:Y.toSubtypey₁✝:X.toSubtypey₂✝:X.toSubtypehx:(fun y x => f.to_fn x = y) x✝ y₁✝hx':(fun y x => f.to_fn x = y) x✝ y₂✝⊢ y₁✝ = y₂✝; inst✝:SetTheoryX:SetY:Setf:Function X Yh:f.bijectivex✝:Y.toSubtypey₁✝:X.toSubtypey₂✝:X.toSubtypehx:f.to_fn y₁✝ = x✝hx':f.to_fn y₂✝ = x✝⊢ y₁✝ = y₂✝
inst✝:SetTheoryX:SetY:Setf:Function X Yh:f.bijectivex✝:Y.toSubtypey₁✝:X.toSubtypey₂✝:X.toSubtypehx:f.to_fn y₁✝ = f.to_fn y₂✝hx':f.to_fn y₂✝ = x✝⊢ y₁✝ = y₂✝
inst✝:SetTheoryX:SetY:Setf:Function X Yh:f.bijectivex✝:Y.toSubtypey₁✝:X.toSubtypey₂✝:X.toSubtypehx:f.to_fn y₁✝ = f.to_fn y₂✝hx':f.to_fn y₂✝ = x✝⊢ f.to_fn y₁✝ = f.to_fn y₂✝
All goals completed! 🐙
)theorem Function.inverse_eval {X Y: Set} {f: Function X Y} (h: f.bijective) (y: Y) (x: X) :
x = (f.inverse h) y ↔ f x = y := Function.eval _ _ _Compatibility with Mathlib's notion of inverse
theorem Function.inverse_eq {X Y: Set} [Nonempty X] {f: Function X Y} (h: f.bijective) :
(f.inverse h).to_fn = Function.invFun f.to_fn := inst✝¹:SetTheoryX:SetY:Setinst✝:Nonempty X.toSubtypef:Function X Yh:f.bijective⊢ (f.inverse h).to_fn = Function.invFun f.to_fn
inst✝¹:SetTheoryX:SetY:Setinst✝:Nonempty X.toSubtypef:Function X Yh:f.bijectivey:Y.toSubtype⊢ ↑((f.inverse h).to_fn y) = ↑(Function.invFun f.to_fn y); inst✝¹:SetTheoryX:SetY:Setinst✝:Nonempty X.toSubtypef:Function X Yh:f.bijectivey:Y.toSubtype⊢ (f.inverse h).to_fn y = Function.invFun f.to_fn y; inst✝¹:SetTheoryX:SetY:Setinst✝:Nonempty X.toSubtypef:Function X Yh:f.bijectivey:Y.toSubtype⊢ Function.invFun f.to_fn y = (f.inverse h).to_fn y
inst✝¹:SetTheoryX:SetY:Setinst✝:Nonempty X.toSubtypef:Function X Yh:f.bijectivey:Y.toSubtype⊢ f.to_fn (Function.invFun f.to_fn y) = y
All goals completed! 🐙
Exercise 3.3.1. Although a proof operating directly on functions would be shorter,
the spirit of the exercise is to show these using the Function.eq_iff definition.
theorem Function.refl {X Y:Set} (f: Function X Y) : f = f := inst✝:SetTheoryX:SetY:Setf:Function X Y⊢ f = f All goals completed! 🐙theorem Function.symm {X Y:Set} (f g: Function X Y) : f = g ↔ g = f := inst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Y⊢ f = g ↔ g = f All goals completed! 🐙theorem Function.trans {X Y:Set} {f g h: Function X Y} (hfg: f = g) (hgh: g = h) : f = h := inst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Yh:Function X Yhfg:f = ghgh:g = h⊢ f = h All goals completed! 🐙theorem Function.comp_congr {X Y Z:Set} {f f': Function X Y} (hff': f = f') {g g': Function Y Z}
(hgg': g = g') : g ○ f = g' ○ f' := inst✝:SetTheoryX:SetY:SetZ:Setf:Function X Yf':Function X Yhff':f = f'g:Function Y Zg':Function Y Zhgg':g = g'⊢ g○f = g'○f' All goals completed! 🐙Exercise 3.3.2
theorem Function.comp_of_inj {X Y Z:Set} {f: Function X Y} {g : Function Y Z} (hf: f.one_to_one)
(hg: g.one_to_one) : (g ○ f).one_to_one := inst✝:SetTheoryX:SetY:SetZ:Setf:Function X Yg:Function Y Zhf:f.one_to_onehg:g.one_to_one⊢ (g○f).one_to_one All goals completed! 🐙theorem Function.comp_of_surj {X Y Z:Set} {f: Function X Y} {g : Function Y Z} (hf: f.onto)
(hg: g.onto) : (g ○ f).onto := inst✝:SetTheoryX:SetY:SetZ:Setf:Function X Yg:Function Y Zhf:f.ontohg:g.onto⊢ (g○f).onto All goals completed! 🐙Exercise 3.3.3 - fill in the sorrys in the statements in a reasonable fashion.
theorem empty_function_one_to_one_iff (X: Set) (f: Function ∅ X) : f.one_to_one ↔ sorry := inst✝:SetTheoryX:Setf:Function ∅ X⊢ f.one_to_one ↔ sorry All goals completed! 🐙theorem empty_function_onto_iff (X: Set) (f: Function ∅ X) : f.onto ↔ sorry := inst✝:SetTheoryX:Setf:Function ∅ X⊢ f.onto ↔ sorry All goals completed! 🐙theorem empty_function_bijective_iff (X: Set) (f: Function ∅ X) : f.bijective ↔ sorry:= inst✝:SetTheoryX:Setf:Function ∅ X⊢ f.bijective ↔ sorry All goals completed! 🐙Exercise 3.3.4.
theorem Function.comp_cancel_left {X Y Z:Set} {f f': Function X Y} {g : Function Y Z}
(heq : g ○ f = g ○ f') (hg: g.one_to_one) : f = f' := inst✝:SetTheoryX:SetY:SetZ:Setf:Function X Yf':Function X Yg:Function Y Zheq:g○f = g○f'hg:g.one_to_one⊢ f = f' All goals completed! 🐙theorem Function.comp_cancel_right {X Y Z:Set} {f: Function X Y} {g g': Function Y Z}
(heq : g ○ f = g' ○ f) (hf: f.onto) : g = g' := inst✝:SetTheoryX:SetY:SetZ:Setf:Function X Yg:Function Y Zg':Function Y Zheq:g○f = g'○fhf:f.onto⊢ g = g' All goals completed! 🐙def Function.comp_cancel_left_without_hg : Decidable (∀ (X Y Z:Set) (f f': Function X Y) (g : Function Y Z) (heq : g ○ f = g ○ f'), f = f') := inst✝:SetTheory⊢ Decidable (∀ (X Y Z : Set) (f f' : Function X Y) (g : Function Y Z), g○f = g○f' → f = f')
-- the first line of this construction should be either `apply isTrue` or `apply isFalse`.
All goals completed! 🐙def Function.comp_cancel_right_without_hg : Decidable (∀ (X Y Z:Set) (f: Function X Y) (g g': Function Y Z) (heq : g ○ f = g' ○ f), g = g') := inst✝:SetTheory⊢ Decidable (∀ (X Y Z : Set) (f : Function X Y) (g g' : Function Y Z), g○f = g'○f → g = g')
-- the first line of this construction should be either `apply isTrue` or `apply isFalse`.
All goals completed! 🐙Exercise 3.3.5.
theorem Function.comp_injective {X Y Z:Set} {f: Function X Y} {g : Function Y Z} (hinj :
(g ○ f).one_to_one) : f.one_to_one := inst✝:SetTheoryX:SetY:SetZ:Setf:Function X Yg:Function Y Zhinj:(g○f).one_to_one⊢ f.one_to_one All goals completed! 🐙theorem Function.comp_surjective {X Y Z:Set} {f: Function X Y} {g : Function Y Z} (hsurj :
(g ○ f).onto) : g.onto := inst✝:SetTheoryX:SetY:SetZ:Setf:Function X Yg:Function Y Zhsurj:(g○f).onto⊢ g.onto All goals completed! 🐙def Function.comp_injective' : Decidable (∀ (X Y Z:Set) (f: Function X Y) (g : Function Y Z) (hinj :
(g ○ f).one_to_one), g.one_to_one) := inst✝:SetTheory⊢ Decidable (∀ (X Y Z : Set) (f : Function X Y) (g : Function Y Z), (g○f).one_to_one → g.one_to_one)
-- the first line of this construction should be either `apply isTrue` or `apply isFalse`.
All goals completed! 🐙def Function.comp_surjective' : Decidable (∀ (X Y Z:Set) (f: Function X Y) (g : Function Y Z) (hsurj :
(g ○ f).onto), f.onto) := inst✝:SetTheory⊢ Decidable (∀ (X Y Z : Set) (f : Function X Y) (g : Function Y Z), (g○f).onto → f.onto)
-- the first line of this construction should be either `apply isTrue` or `apply isFalse`.
All goals completed! 🐙Exercise 3.3.6
theorem Function.inverse_comp_self {X Y: Set} {f: Function X Y} (h: f.bijective) (x: X) :
(f.inverse h) (f x) = x := inst✝:SetTheoryX:SetY:Setf:Function X Yh:f.bijectivex:X.toSubtype⊢ (f.inverse h).to_fn (f.to_fn x) = x All goals completed! 🐙theorem Function.self_comp_inverse {X Y: Set} {f: Function X Y} (h: f.bijective) (y: Y) :
f ((f.inverse h) y) = y := inst✝:SetTheoryX:SetY:Setf:Function X Yh:f.bijectivey:Y.toSubtype⊢ f.to_fn ((f.inverse h).to_fn y) = y All goals completed! 🐙theorem Function.inverse_bijective {X Y: Set} {f: Function X Y} (h: f.bijective) :
(f.inverse h).bijective := inst✝:SetTheoryX:SetY:Setf:Function X Yh:f.bijective⊢ (f.inverse h).bijective All goals completed! 🐙theorem Function.inverse_inverse {X Y: Set} {f: Function X Y} (h: f.bijective) :
(f.inverse h).inverse (f.inverse_bijective h) = f := inst✝:SetTheoryX:SetY:Setf:Function X Yh:f.bijective⊢ (f.inverse h).inverse ⋯ = f All goals completed! 🐙theorem Function.comp_bijective {X Y Z:Set} {f: Function X Y} {g : Function Y Z} (hf: f.bijective)
(hg: g.bijective) : (g ○ f).bijective := inst✝:SetTheoryX:SetY:SetZ:Setf:Function X Yg:Function Y Zhf:f.bijectivehg:g.bijective⊢ (g○f).bijective All goals completed! 🐙Exercise 3.3.7
theorem Function.inv_of_comp {X Y Z:Set} {f: Function X Y} {g : Function Y Z}
(hf: f.bijective) (hg: g.bijective) :
(g ○ f).inverse (Function.comp_bijective hf hg) = (f.inverse hf) ○ (g.inverse hg) := inst✝:SetTheoryX:SetY:SetZ:Setf:Function X Yg:Function Y Zhf:f.bijectivehg:g.bijective⊢ (g○f).inverse ⋯ = f.inverse hf○g.inverse hg All goals completed! 🐙Exercise 3.3.8
abbrev Function.inclusion {X Y:Set} (h: X ⊆ Y) :
Function X Y := Function.mk_fn (fun x ↦ ⟨ x.val, h x.val x.property ⟩ )abbrev Function.id (X:Set) : Function X X := Function.mk_fn (fun x ↦ x)theorem Function.inclusion_id (X:Set) :
Function.inclusion (SetTheory.Set.subset_self X) = Function.id X := inst✝:SetTheoryX:Set⊢ inclusion ⋯ = id X All goals completed! 🐙theorem Function.inclusion_comp (X Y Z:Set) (hXY: X ⊆ Y) (hYZ: Y ⊆ Z) :
Function.inclusion hYZ ○ Function.inclusion hXY = Function.inclusion (SetTheory.Set.subset_trans hXY hYZ) := inst✝:SetTheoryX:SetY:SetZ:SethXY:X ⊆ YhYZ:Y ⊆ Z⊢ inclusion hYZ○inclusion hXY = inclusion ⋯ All goals completed! 🐙theorem Function.comp_id {A B:Set} (f: Function A B) : f ○ Function.id A = f := inst✝:SetTheoryA:SetB:Setf:Function A B⊢ f○id A = f All goals completed! 🐙theorem Function.id_comp {A B:Set} (f: Function A B) : Function.id B ○ f = f := inst✝:SetTheoryA:SetB:Setf:Function A B⊢ id B○f = f All goals completed! 🐙theorem Function.comp_inv {A B:Set} (f: Function A B) (hf: f.bijective) :
f ○ f.inverse hf = Function.id B := inst✝:SetTheoryA:SetB:Setf:Function A Bhf:f.bijective⊢ f○f.inverse hf = id B All goals completed! 🐙theorem Function.inv_comp {A B:Set} (f: Function A B) (hf: f.bijective) :
f.inverse hf ○ f = Function.id A := inst✝:SetTheoryA:SetB:Setf:Function A Bhf:f.bijective⊢ f.inverse hf○f = id A All goals completed! 🐙open Classical in
theorem Function.glue {X Y Z:Set} (hXY: Disjoint X Y) (f: Function X Z) (g: Function Y Z) :
∃! h: Function (X ∪ Y) Z, (h ○ Function.inclusion (SetTheory.Set.subset_union_left X Y) = f)
∧ (h ○ Function.inclusion (SetTheory.Set.subset_union_right X Y) = g) := inst✝:SetTheoryX:SetY:SetZ:SethXY:Disjoint X Yf:Function X Zg:Function Y Z⊢ ∃! h, h○inclusion ⋯ = f ∧ h○inclusion ⋯ = g All goals completed! 🐙open Classical in
theorem Function.glue' {X Y Z:Set} (f: Function X Z) (g: Function Y Z)
(hfg : ∀ x : ((X ∩ Y): Set), f ⟨x.val, inst✝:SetTheoryX:SetY:SetZ:Setf:Function X Zg:Function Y Zx:(X ∩ Y).toSubtype⊢ ↑x ∈ X All goals completed! 🐙⟩ = g ⟨x.val, inst✝:SetTheoryX:SetY:SetZ:Setf:Function X Zg:Function Y Zx:(X ∩ Y).toSubtype⊢ ↑x ∈ Y All goals completed! 🐙⟩) :
∃! h: Function (X ∪ Y) Z, (h ○ Function.inclusion (SetTheory.Set.subset_union_left X Y) = f)
∧ (h ○ Function.inclusion (SetTheory.Set.subset_union_right X Y) = g) := inst✝:SetTheoryX:SetY:SetZ:Setf:Function X Zg:Function Y Zhfg:∀ (x : (X ∩ Y).toSubtype), f.to_fn ⟨↑x, ⋯⟩ = g.to_fn ⟨↑x, ⋯⟩⊢ ∃! h, h○inclusion ⋯ = f ∧ h○inclusion ⋯ = g All goals completed! 🐙end Chapter3