Imports
import Mathlib.Tactic import Analysis.Section_3_1 import Analysis.Tools.ExistsUnique
set_option doc.verso.suggestions false

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

  • Various relations with the Mathlib notion of a function X → Y between two types X, Y. (Note from Section 3.1 that every Set X can also be viewed as a subtype {x : Object // x ∈ X } of 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 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
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#check Function.mk
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 f: Function X Y to a Mathlib function f: X Y. 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 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.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! 🐙 intro y 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: := nat_equiv.symm x, hx1∃! 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: := nat_equiv.symm x, hx1this:x = nhx2:¬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: := nat_equiv.symm x, hx1this:x = nhx2:n = n - 1 + 1nat_equiv.symm (n - 1) + 1 = ninst✝:SetTheoryx:Objecthx:x Nat \ {0}hx1:x Natn: := nat_equiv.symm x, hx1this:x = nhx2:n = n - 1 + 1 (y : Nat.toSubtype), nat_equiv.symm y + 1 = n y = (n - 1) inst✝:SetTheoryx:Objecthx:x Nat \ {0}hx1:x Natn: := nat_equiv.symm x, hx1this:x = nhx2:n = n - 1 + 1nat_equiv.symm (n - 1) + 1 = n All goals completed! 🐙 intro y inst✝:SetTheoryx:Objecthx:x Nat \ {0}hx1:x Natn: := nat_equiv.symm x, hx1this:x = nhx2:n = n - 1 + 1y: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 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 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 {name}`NNReal` and {lean}`ℝ`. -/ 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: := f (-1)False have h1 := (hf _ y).mp (inst✝:SetTheoryf: hf: (x y : ), y = f x y ^ 2 = xy: := f (-1)y = f ?m.51 All goals completed! 🐙) inst✝:SetTheoryf: hf: (x y : ), y = f x y ^ 2 = xy: := f (-1)h1:y ^ 2 = -1h2:0 y ^ 2False 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: := f 4hf: (y_1 : ), y_1 = y y_1 ^ 2 = 4False have hy := (hf y).mp (inst✝:SetTheoryf:NNReal y: := f 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: := f 4hf: (y_1 : ), y_1 = y y_1 ^ 2 = 4hy:y ^ 2 = 42 ^ 2 = 4 All goals completed! 🐙) have h2 : -2 = y := (hf (-2)).mpr (inst✝:SetTheoryf:NNReal y: := f 4hf: (y_1 : ), y_1 = y y_1 ^ 2 = 4hy:y ^ 2 = 4h1:2 = y(-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; intro 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 _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 simp_rw inst✝:SetTheoryf_3_3_10a = f_3_3_10bFunction.eq_iff, Function.eval_of] 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| simp_rw inst✝:SetTheory(fun x x) = fun x |x|NNReal.abs_eq]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: := (fun x x) (-1)False inst✝:SetTheoryh:(fun x x) = fun x |x|a: := (fun x x) (-1)b: := (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: := (fun x x) (-1)b: := (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_1 True) x y inst✝:SetTheoryX:Setx:Objecthx:x ∃! y, (fun x x_1 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. 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 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' intro _ inst✝:SetTheoryx✝:Nat.toSubtypex'✝: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 = 1h2:(fun n n ^ 2) (-1) = (fun n n ^ 2) 1False inst✝:SetTheoryh1:(fun n n ^ 2) 1 = 1h2:(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 intro _ inst✝:SetTheorya₁✝:a₂✝:(fun n n ^ 2) a₁✝ = (fun n n ^ 2) a₂✝ a₁✝ = a₂✝ 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, intro _ 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¬Function.Bijective fun n n + 1 inst✝:SetTheoryh:¬Function.Surjective fun n n + 1¬((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:Function ?m.31 Nat := mk_fn fun x 0 f, (∀ (x : Nat.toSubtype), ∃! y, y = f.to_fn x) ¬f.bijective; inst✝:SetTheoryf:Function ?m.31 Nat := mk_fn fun x 0(∀ (x : Nat.toSubtype), ∃! y, y = f.to_fn x) ¬f.bijective inst✝:SetTheoryf:Function ?m.31 Nat := mk_fn fun x 0 (x : Nat.toSubtype), ∃! y, y = f.to_fn xinst✝:SetTheoryf:Function ?m.31 Nat := mk_fn fun x 0¬f.bijective inst✝:SetTheoryf:Function ?m.31 Nat := mk_fn fun x 0 (x : Nat.toSubtype), ∃! y, y = f.to_fn x inst✝:SetTheoryf:Function ?m.31 Nat := mk_fn fun x 0x✝:Nat.toSubtype∃! y, y = f.to_fn x✝ inst✝:SetTheoryf:Function ?m.31 Nat := mk_fn fun x 0x✝:Nat.toSubtype x, x = f.to_fn x✝inst✝:SetTheoryf:Function ?m.31 Nat := 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:Function ?m.31 Nat := mk_fn fun x 0x✝:Nat.toSubtype x, x = f.to_fn x✝ inst✝:SetTheoryf:Function ?m.31 Nat := mk_fn fun x 0x✝:Nat.toSubtype0 = f.to_fn x✝; All goals completed! 🐙 inst✝:SetTheoryf:Function ?m.31 Nat := 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:Function ?m.31 Nat := 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:Function ?m.31 Nat := mk_fn fun x 0¬(f.one_to_one f.onto) suffices h : ¬ f.one_to_one inst✝:SetTheoryf:Function Nat Nat := mk_fn fun x 0h:¬f.one_to_one¬(f.one_to_one f.onto) All goals completed! 🐙 inst✝:SetTheoryf:Function ?m.31 Nat := mk_fn fun x 0¬ (x x' : Nat.toSubtype), f.to_fn x = f.to_fn x' x = x' inst✝:SetTheoryf:Function ?m.31 Nat := mk_fn fun x 0 x x', f.to_fn x = f.to_fn x' x x'; inst✝:SetTheoryf:Function ?m.31 Nat := mk_fn fun x 0f.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! 🐙 intro _ inst✝:SetTheoryX:SetY:Setf:Function X Yh:f.bijectivex✝:Y.toSubtypey₁✝:X.toSubtypey₂✝: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.toSubtypey₁✝:X.toSubtypey₂✝:X.toSubtypehx:(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.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 Function.­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! 🐙

Exercise 3.3.7

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! 🐙
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