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 Unknown identifier `Function`Function X Y between two sets Unknown identifier `X`X, Unknown identifier `Y`Y in the set theory of Section 3.1

  • Various relations with the Mathlib notion of a function Unknown identifier `X`sorry sorry : Sort (imax u_1 u_2)X Unknown identifier `Y`Y between two types Unknown identifier `X`X, Unknown identifier `Y`Y. (Note from Section 3.1 that every Set.{u} (α : Type u) : Type uSet Unknown identifier `X`X can also be viewed as a subtype { x // x sorry } : Type u_1{x : Unknown identifier `Object`Object // x Unknown identifier `X`X } of Unknown identifier `Object`Object.)

  • 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 : Type or : Type that have not been implemented in the Chapter 3 framework.

We will work here with the version Nat : TypeNat 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 : Type.

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 sorry sorry : Type u_2Function Unknown identifier `X`X Unknown identifier `Y`Y is the structure of functions from Unknown identifier `X`X to Unknown identifier `Y`Y. Analogous to the Mathlib type Unknown identifier `X`sorry sorry : Sort (imax u_1 u_2)X Unknown identifier `Y`Y.

@[ext] structure Function (X Y: Set) where P : X Y Prop unique : x: X, ∃! y: Y, P x y
Chapter3.Function.mk.{u_1, u_2} [SetTheory] {X Y : Set} (P : X.toSubtype  Y.toSubtype  Prop)
  (unique :  (x : X.toSubtype), ∃! y, P x y) : Function 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).choose
noncomputable 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 Chapter3.Function.{u_1, u_2} [SetTheory] (X Y : Set) : Type u_2Function

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.toSubtypey = 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.toSubtypef x = (mk_fn f).to_fn x; All goals completed! 🐙

Example 3.3.3.

abbrev P_3_3_3a : Nat Nat Prop := fun x y (y:) = (x:)+1
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.toSubtypeP_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.toSubtypeP_3_3_3a x (nat_equiv.symm x + 1) All goals completed! 🐙 inst✝:SetTheoryx:Nat.toSubtypey:Nat.toSubtypeh:P_3_3_3a x yy = (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 yFalse 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 = nFalse 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.50449this:_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.50449this:_fvar.50161 = _fvar.50593 := ?_mvar.51000hx2:_fvar.50593 = _fvar.50593 - 1 + 1 := ?_mvar.59231nat_equiv.symm (n - 1) + 1 = ninst✝:SetTheoryx:Objecthx:x Nat \ {0}hx1:x Natn: := Chapter3.SetTheory.Set.nat_equiv.symm _fvar.50161, _fvar.50449this:_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.50449this:_fvar.50161 = _fvar.50593 := ?_mvar.51000hx2:_fvar.50593 = _fvar.50593 - 1 + 1 := ?_mvar.59231nat_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.50449this:_fvar.50161 = _fvar.50593 := ?_mvar.51000hx2:_fvar.50593 = _fvar.50593 - 1 + 1 := ?_mvar.59231y:Nat.toSubtypehy:nat_equiv.symm y + 1 = ny = (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 Unknown identifier `n`n inside Nat \ {0} : SetNat \ {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 0n Nat \ {0} inst✝:SetTheoryn:h:n 0n Nat inst✝:SetTheoryn:h:n 0n 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✝:SetTheory4 0 All goals completed! 🐙)) = 3 := inst✝:SetTheoryf_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 : TypeNNReal and : Type.

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 = xFalse inst✝:SetTheoryf: hf: (x y : ), y = f x y ^ 2 = xFalse; 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.81471False 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 = xFalse inst✝:SetTheoryf:NNReal hf: (x : NNReal) (y : ), y = f x y ^ 2 = xFalse; inst✝:SetTheoryf:NNReal hf: (y : ), y = f 4 y ^ 2 = 4False; inst✝:SetTheoryf:NNReal y: := @_fvar.82895 4hf: (y_1 : ), y_1 = y y_1 ^ 2 = 4False have hy := (hf y).mp (inst✝:SetTheoryf:NNReal y: := @_fvar.82895 4hf: (y_1 : ), y_1 = y y_1 ^ 2 = 4y = 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:NNRealy = NNReal.sqrt x y ^ 2 = x inst✝:SetTheoryx:NNRealy:NNRealy = NNReal.sqrt x y ^ 2 = xinst✝:SetTheoryx:NNRealy:NNRealy ^ 2 = x y = NNReal.sqrt x inst✝:SetTheoryx:NNRealy:NNRealy = NNReal.sqrt x y ^ 2 = xinst✝:SetTheoryx:NNRealy:NNRealy ^ 2 = x y = NNReal.sqrt x inst✝:SetTheoryx:NNRealy:NNRealh:y ^ 2 = xy = NNReal.sqrt x inst✝:SetTheoryx:NNRealy:NNRealh:y = NNReal.sqrt xy ^ 2 = x All goals completed! 🐙 inst✝:SetTheoryx:NNRealy:NNRealh:y ^ 2 = xy = NNReal.sqrt x All goals completed! 🐙

Example 3.3.5. The unused variable Unknown identifier `_x`_x is underscored to avoid triggering a linter.

abbrev SetTheory.Set.P_3_3_5 : Nat Nat Prop := fun _x y y = 7
theorem 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.toSubtypeP_3_3_5 x 7inst✝:SetTheoryx:Nat.toSubtype (y : Nat.toSubtype), P_3_3_5 x y y = 7 inst✝:SetTheoryx:Nat.toSubtypeP_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.toSubtypef_3_3_5.to_fn x = 7 inst✝:SetTheoryx:Nat.toSubtype7 = 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 Yf = g (x : X.toSubtype), f.to_fn x = g.to_fn x inst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Yf = 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 Yf = 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 xf = 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.toSubtypef.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.toSubtypef.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.toSubtypeg.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.toSubtypef.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.toSubtypeg.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 yf.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 yg.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 yf.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 yg.P x y

Example 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✝:SetTheoryf_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.toSubtypenat_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 declaration uses 'sorry'SetTheory.Set.empty_function_unique {X: Set} (f g: Function (:Set) X) : f = g := inst✝:SetTheoryX:Setf:Function Xg:Function Xf = 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(gf).to_fn = g.to_fn f.to_fn inst✝:SetTheoryX:SetY:SetZ:Setg:Function Y Zf:Function X Yx✝:X.toSubtype((gf).to_fn x✝) = ((g.to_fn f.to_fn) x✝); All goals completed! 🐙

Example 3.3.14

abbrev SetTheory.Set.f_3_3_14 : Function Nat Nat := Function.mk_fn (fun x (2*x:))
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✝:SetTheoryg_3_3_14f_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✝:SetTheoryf_3_3_14g_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✝ Nat2 * (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 Xh(gf) = (hg)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 Yf.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.toSubtypex 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.{u₁, u₂} {α : Sort u₁} {β : Sort u₂} (f : α β) : PropFunction.Injective. You may wish to use the Unknown identifier `unfold`unfold tactic to understand Mathlib concepts such as Function.Injective.{u₁, u₂} {α : Sort u₁} {β : Sort u₂} (f : α β) : PropFunction.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 Yf.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 ^ 2False 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) 1False inst✝:SetTheoryh1:(fun n => n ^ 2) 1 = 1 := ?_mvar.127345h2:(fun n => n ^ 2) (-1) = (fun n => n ^ 2) 1h:-1 = 1False All goals completed! 🐙example : Function.Injective (fun (n:) n^2) := inst✝:SetTheoryFunction.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✝:SetTheoryFunction.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₂✝ ^ 2

Remark 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 = y

Compatibility 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 Yf.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✝:SetTheoryFunction.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.onto

Compatibility 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 Yf.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 33 {3, 4} All goals completed! 🐙 | 1 => 3, inst✝:SetTheoryx:Fin 33 {3, 4} All goals completed! 🐙 | 2 => 4, inst✝:SetTheoryx:Fin 34 {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 22 {2, 3, 4} All goals completed! 🐙 | 1 => 3, inst✝:SetTheoryx:Fin 23 {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 33 {3, 4, 5} All goals completed! 🐙 | 1 => 4, inst✝:SetTheoryx:Fin 34 {3, 4, 5} All goals completed! 🐙 | 2 => 5, inst✝:SetTheoryx:Fin 35 {3, 4, 5} All goals completed! 🐙 example : Function.Bijective h_3_3_24 := inst✝:SetTheoryFunction.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✝:SetTheoryFunction.Bijective fun n => n + 1, inst✝:SetTheoryFunction.Injective fun n => n + 1, inst✝:SetTheoryFunction.Surjective fun n => n + 1, inst✝:SetTheoryFunction.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 0x - 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.toSubtype0 = 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 => 0f.to_fn 0 = f.to_fn 1 0 1; All goals completed! 🐙

We cannot use the notation Unknown identifier `f`sorry⁻¹ : ?m.1f⁻¹ for the inverse because in Mathlib's Inv.{u} (α : Type u) : Type uInv class, the inverse of Unknown identifier `f`f must be exactly of the same type of Unknown identifier `f`f, and Function sorry sorry : Type u_2Function Unknown identifier `Y`Y Unknown identifier `X`X is a different type from Function sorry sorry : Type u_2Function Unknown identifier `X`X Unknown identifier `Y`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.toSubtypeFunction.invFun f.to_fn y = (f.inverse h).to_fn y inst✝¹:SetTheoryX:SetY:Setinst✝:Nonempty X.toSubtypef:Function X Yh:f.bijectivey:Y.toSubtypef.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 Chapter3.Function.eq_iff.{u_1, u_2} [SetTheory] {X Y : Set} (f g : Function X Y) : f = g (x : X.toSubtype), f.to_fn x = g.to_fn xFunction.eq_iff definition.

theorem declaration uses 'sorry'Function.refl {X Y:Set} (f: Function X Y) : f = f := inst✝:SetTheoryX:SetY:Setf:Function X Yf = f All goals completed! 🐙
theorem declaration uses 'sorry'Function.symm {X Y:Set} (f g: Function X Y) : f = g g = f := inst✝:SetTheoryX:SetY:Setf:Function X Yg:Function X Yf = g g = f All goals completed! 🐙theorem declaration uses 'sorry'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 = hf = h All goals completed! 🐙theorem declaration uses 'sorry'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'gf = g'f' All goals completed! 🐙

Exercise 3.3.2

theorem declaration uses 'sorry'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(gf).one_to_one All goals completed! 🐙
theorem declaration uses 'sorry'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(gf).onto All goals completed! 🐙

Exercise 3.3.3 - fill in the sorrys in the statements in a reasonable fashion.

theorem declaration uses 'sorry'empty_function_one_to_one_iff (X: Set) (f: Function X) : f.one_to_one sorry := inst✝:SetTheoryX:Setf:Function Xf.one_to_one sorry All goals completed! 🐙
theorem declaration uses 'sorry'empty_function_onto_iff (X: Set) (f: Function X) : f.onto sorry := inst✝:SetTheoryX:Setf:Function Xf.onto sorry All goals completed! 🐙theorem declaration uses 'sorry'empty_function_bijective_iff (X: Set) (f: Function X) : f.bijective sorry:= inst✝:SetTheoryX:Setf:Function Xf.bijective sorry All goals completed! 🐙

Exercise 3.3.4.

theorem declaration uses 'sorry'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:gf = gf'hg:g.one_to_onef = f' All goals completed! 🐙
theorem declaration uses 'sorry'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:gf = g'fhf:f.ontog = g' All goals completed! 🐙def declaration uses 'sorry'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✝:SetTheoryDecidable (∀ (X Y Z : Set) (f f' : Function X Y) (g : Function Y Z), gf = gf' f = f') -- the first line of this construction should be either `apply isTrue` or `apply isFalse`. All goals completed! 🐙def declaration uses 'sorry'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✝:SetTheoryDecidable (∀ (X Y Z : Set) (f : Function X Y) (g g' : Function Y Z), gf = 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 declaration uses 'sorry'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:(gf).one_to_onef.one_to_one All goals completed! 🐙
theorem declaration uses 'sorry'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:(gf).ontog.onto All goals completed! 🐙def declaration uses 'sorry'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✝:SetTheoryDecidable (∀ (X Y Z : Set) (f : Function X Y) (g : Function Y Z), (gf).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 declaration uses 'sorry'Function.comp_surjective' : Decidable ( (X Y Z:Set) (f: Function X Y) (g : Function Y Z) (hsurj : (g f).onto), f.onto) := inst✝:SetTheoryDecidable (∀ (X Y Z : Set) (f : Function X Y) (g : Function Y Z), (gf).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 declaration uses 'sorry'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 declaration uses 'sorry'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.toSubtypef.to_fn ((f.inverse h).to_fn y) = y All goals completed! 🐙theorem declaration uses 'sorry'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 declaration uses 'sorry'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 declaration uses 'sorry'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(gf).bijective All goals completed! 🐙

Exercise 3.3.7

theorem declaration uses 'sorry'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(gf).inverse = f.inverse hfg.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 declaration uses 'sorry'Function.inclusion_id (X:Set) : Function.inclusion (SetTheory.Set.subset_self X) = Function.id X := inst✝:SetTheoryX:Setinclusion = id X All goals completed! 🐙theorem declaration uses 'sorry'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 Zinclusion hYZinclusion hXY = inclusion All goals completed! 🐙theorem declaration uses 'sorry'Function.comp_id {A B:Set} (f: Function A B) : f Function.id A = f := inst✝:SetTheoryA:SetB:Setf:Function A Bfid A = f All goals completed! 🐙theorem declaration uses 'sorry'Function.id_comp {A B:Set} (f: Function A B) : Function.id B f = f := inst✝:SetTheoryA:SetB:Setf:Function A Bid Bf = f All goals completed! 🐙theorem declaration uses 'sorry'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.bijectiveff.inverse hf = id B All goals completed! 🐙theorem declaration uses 'sorry'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.bijectivef.inverse hff = id A All goals completed! 🐙open Classical in theorem declaration uses 'sorry'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, hinclusion = f hinclusion = g All goals completed! 🐙open Classical in theorem declaration uses 'sorry'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).toSubtypex X All goals completed! 🐙 = g x.val, inst✝:SetTheoryX:SetY:SetZ:Setf:Function X Zg:Function Y Zx:(X Y).toSubtypex 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, hinclusion = f hinclusion = g All goals completed! 🐙end Chapter3