1-- Counting injections: the falling factorial n · (n − 1) ⋯ (n − m + 1)2-- counts the injections from an m-element set into an n-element set, and3-- the bijections between two n-element sets number n!4-- Part of Cumulus, the Grace17 mathematics library.5-- Copyright (c) 2026 Grant Passmore.6-- Released under the Apache License 2.0. See LICENSE in the repository root.7-- Authors: Grant Passmore89module Grace.Cumulus.Combinatorics.Injections10import Functions1112def injections (A B : Set) : Set:=13 { f ∈ functionSpace(A, B) | InjectiveBetween(f, A, B) }1415theorem injections.of_injective (f A B : Set)16requires injective : InjectiveBetween(f, A, B)17shows f ∈ injections(A, B)18proof19have function := Injective.function with injective20have inSpace := functionSpace.mem_iff.backward with function21exact injections.membership.backward with⟨inSpace, injective⟩2223theorem injections.injective (f A B : Set)24requires member : f ∈ injections(A, B)25shows InjectiveBetween(f, A, B)26proof27have parts := injections.membership.forward with member28exact parts.right2930theorem injections.function (f A B : Set)31requires member : f ∈ injections(A, B)32shows f : A → B33proof34exact Injective.function with (injections.injective with member)3536theorem injections.subset (A B : Set)37shows injections(A, B) ⊆ functionSpace(A, B)38proof39intros f hf40have parts := injections.membership.forward with hf41exact parts.left4243theorem injections.finite (A B : Set)44requires finiteA : Finite(A)45requires finiteB : Finite(B)46shows Finite(injections(A, B))47proof48have space := functionSpace.finite with finiteA, finiteB49exact Finite.subset with space, (injections.subset at A, B)5051theorem injections.empty_domain (B : Set)52shows injections(∅, B) = {∅}53proof54have emptyFunction := FunctionBetween.empty at B55have emptyInjective : InjectiveBetween(∅, ∅, B)56unfold InjectiveBetween57refine⟨emptyFunction, ?_⟩58intros u impossible59exfalso60exactset.empty with impossible61ext f62constructor63 . intro member64have parts := injections.membership.forward with member65have inSpace := parts.left66rw functionSpace.empty_domain at inSpace67exact inSpace68 . intro member69have equal := singleton.membership.forward with member70rw equal71exact injections.of_injective with emptyInjective7273theorem injections.empty_domain_count (B : Set)74shows cardinality(injections(∅, B)) =175proof76rw injections.empty_domain77exact cardinality.singleton at∅7879theorem injections.empty_codomain (A : Set)80requires nonempty : Nonempty(A)81shows injections(A, ∅) =∅82proof83have empty := functionSpace.empty_codomain with nonempty84have subset := injections.subset at A, ∅85rw empty at subset86exact Subset.empty_iff.forward with subset8788-- The falling factorial n · (n − 1) ⋯ (n − m + 1), zero once m exceeds n.89def fallingFactorial (n m : Nat) →Nat90| n, zero =>191| n, succ(m) => mul(fallingFactorial(n, m), sub(n, m))92descends m9394theorem fallingFactorial.zero (n : Nat)95shows fallingFactorial(n, 0) =196proof97simp [fallingFactorial]9899theorem fallingFactorial.succ (n m : Nat)100shows fallingFactorial(n, m +1) = fallingFactorial(n, m) * (n - m)101proof102have hm : m +1= succ(m) := add.right_one with*103rw hm104simp [fallingFactorial]105106theorem fallingFactorial.natural (n m : Nat)107showsNat(fallingFactorial(n, m))108proof109induction m110| zero =>111rw fallingFactorial.zero112typecheck113| j +1using ih =>114rw fallingFactorial.succ115have subNat := sub.closed at n, j116typecheck117118theorem fallingFactorial.one (n : Nat)119shows fallingFactorial(n, 1) = n120proof121have one : 0+1=1bycompute122rw← one123rw [fallingFactorial.succ, fallingFactorial.zero, sub.zero_right]124ring125126theorem fallingFactorial.zero_left (m : Nat)127shows fallingFactorial(0, m +1) =0128proof129rw [fallingFactorial.succ, sub.zero_left]130have natural := fallingFactorial.natural at0, m131ring132133-- The recursion on the first argument, free of subtraction.134theorem fallingFactorial.succ_succ (n m : Nat)135shows fallingFactorial(n +1, m +1) = (n +1) * fallingFactorial(n, m)136proof137induction m138| zero =>139have one : 0+1=1bycompute140rw [one, fallingFactorial.one, fallingFactorial.zero]141ring142| j +1using ih =>143rw [fallingFactorial.succ, ih]144have hn : n +1= succ(n) := add.right_one with*145have hj : j +1= succ(j) := add.right_one with*146rw [hn, hj, sub.succ_succ, ← hj]147rw fallingFactorial.succ148have natural := fallingFactorial.natural at n, j149have subNat := sub.closed at n, j150ring151152theorem fallingFactorial.self (n : Nat)153shows fallingFactorial(n, n) = n!154proof155induction n156| zero =>compute157| k +1using ih =>158rw [fallingFactorial.succ_succ, ih, factorial.succ]159rfl160161theorem fallingFactorial.self_vanishes (n : Nat)162shows fallingFactorial(n, n +1) =0163proof164rw fallingFactorial.succ165have shape : 0+ n = n byring166have difference : n - n =0167have step := sub.add_right at0, n168rw shape at step169exact step170rw difference171have natural := fallingFactorial.natural at n, n172ring173174theorem fallingFactorial.beyond (n d : Nat)175shows fallingFactorial(n, n +1+ d) =0176proof177induction d178| zero =>179have shape : n +1+0= n +1byring180rw shape181exact fallingFactorial.self_vanishes at n182| j +1using ih =>183have shape : n +1+ (j +1) = (n +1+ j) +1byring184rw [shape, fallingFactorial.succ, ih]185have subNat := sub.closed at n, n +1+ j186ring187188theorem fallingFactorial.of_Less (n m : Nat)189requires below : n < m190shows fallingFactorial(n, m) =0191proof192obtain⟨d, dNat, shape⟩:= below193have form : m = n +1+ d194rw← shape195ring196rw form197exact fallingFactorial.beyond at n, d198199theorem fallingFactorial.mul_factorial (k : Nat)200shows∀ d, Nat(d) → fallingFactorial(k + d, k) * d! = (k + d)!201proof202induction k203| zero =>204intros d dNat205have shape : 0+ d = d byring206rw [shape, fallingFactorial.zero]207have closed := factorial.closed at d208ring209| j +1using ih =>210intros d dNat211have shape : j +1+ d = (j + d) +1byring212rw [shape, fallingFactorial.succ_succ]213have inner := ih with d, dNat214rw factorial.succ215have natural := fallingFactorial.natural at j + d, j216have closedD := factorial.closed at d217have closedTop := factorial.closed at j + d218ring [inner]219220-- The falling factorial is the binomial coefficient times k!.221theorem fallingFactorial.choose (n k : Nat)222requires le : k ≤ n223shows fallingFactorial(n, k) = (n choose k) * k!224proof225obtain⟨d, dNat, shape⟩:= le226have form : n = k + d227rw← shape228rfl229rw form230have row := fallingFactorial.mul_factorial at k231have first := row with d, dNat232have commute : k + d = d + k byring233have chooseRow := choose.factorial at d234have second := chooseRow with k, assumption235rw← commute at second236have natural := fallingFactorial.natural at k + d, k237have chooseNat := choose.natural at k + d, k238have closedK := factorial.closed at k239have closedD := factorial.closed at d240have nonzero := factorial.nonzero at d241have balanced : d! * fallingFactorial(k + d, k) = d! * (((k + d) choose k) * k!) byring [first, second]242exact mul.left_cancel_positive with nonzero, balanced243244-- Changing the codomain of an injection.245theorem Injective.widen (f A B C : Set)246requires injective : InjectiveBetween(f, A, B)247requires subset : B ⊆ C248shows InjectiveBetween(f, A, C)249proof250have function := Injective.function with injective251have values : ∀ x ∈ A, f(x) ∈ C252intros x hx253exact subset with f(x), (FunctionBetween.apply_closed with function, hx)254have widened := FunctionBetween.codomain_of_values with function, values255apply Injective.of_pointwise with widened256intros x hx y hy same257exact Injective.apply_cancel with injective, hx, hy, same258259theorem Injective.avoid (g A B b : Set)260requires injective : InjectiveBetween(g, A, B)261requires absent : ¬b ∈ functionImage(g, A, B)262shows InjectiveBetween(g, A, B ∖ {b})263proof264have function := Injective.function with injective265have values : ∀ x ∈ A, g(x) ∈ B ∖ {b}266intros x hx267apply difference.singleton_membership.backward268constructor269 . exact FunctionBetween.apply_closed with function, hx270 . intro same271apply absent272rw← same273exact functionImage.value with function, hx274have narrowed := FunctionBetween.codomain_of_values with function, values275apply Injective.of_pointwise with narrowed276intros x hx y hy same277exact Injective.apply_cancel with injective, hx, hy, same278279-- Pairs of an injection on A and a point of B, split by whether the point280-- is already a value.281def freshPairs (A B : Set) : Set:=282 { p ∈ injections(A, B) × B |∃ g ∈ injections(A, B), ∃ b ∈ B, p = (g, b) ∧¬b ∈ functionImage(g, A, B) }283284def coveredPairs (A B : Set) : Set:=285 { p ∈ injections(A, B) × B |∃ g ∈ injections(A, B), ∃ b ∈ B, p = (g, b) ∧ b ∈ functionImage(g, A, B) }286287theorem freshPairs.pair (A B g b : Set)288shows289 (g, b) ∈ freshPairs(A, B) ↔ g ∈ injections(A, B) ∧ b ∈ B ∧¬b ∈ functionImage(g, A, B)290proof291constructor292 . intro member293obtain⟨bound, h, hh, c, hc, shape, absent⟩:= freshPairs.membership.forward with member294have coordinates := orderedPair.injective with shape295rw [coordinates.left, coordinates.right]296exact⟨hh, hc, absent⟩297 . intro parts298obtain⟨hg, hb, absent⟩:= parts299apply freshPairs.membership.backward300refine⟨(product.pair with hg, hb), g, hg, b, hb, rfl, absent⟩301302theorem coveredPairs.pair (A B g b : Set)303shows304 (g, b) ∈ coveredPairs(A, B) ↔ g ∈ injections(A, B) ∧ b ∈ B ∧ b ∈ functionImage(g, A, B)305proof306constructor307 . intro member308obtain⟨bound, h, hh, c, hc, shape, covered⟩:= coveredPairs.membership.forward with member309have coordinates := orderedPair.injective with shape310rw [coordinates.left, coordinates.right]311exact⟨hh, hc, covered⟩312 . intro parts313obtain⟨hg, hb, covered⟩:= parts314apply coveredPairs.membership.backward315refine⟨(product.pair with hg, hb), g, hg, b, hb, rfl, covered⟩316317theorem freshPairs.subset (A B : Set)318shows freshPairs(A, B) ⊆ injections(A, B) × B319proof320intros p hp321have parts := freshPairs.membership.forward with hp322exact parts.left323324theorem coveredPairs.subset (A B : Set)325shows coveredPairs(A, B) ⊆ injections(A, B) × B326proof327intros p hp328have parts := coveredPairs.membership.forward with hp329exact parts.left330331theorem freshPairs.disjoint (A B : Set)332shows Disjoint(freshPairs(A, B), coveredPairs(A, B))333proof334apply Disjoint.iff.backward335intros p fresh covered336obtain⟨bound, g, hg, b, hb, shape, absent⟩:= freshPairs.membership.forward with fresh337rw shape at covered338have parts := coveredPairs.pair.forward with covered339exact absent with parts.right.right340341theorem freshPairs.union (A B : Set)342shows freshPairs(A, B) ∪ coveredPairs(A, B) = injections(A, B) × B343proof344ext p345constructor346 . intro hp347havesplit:= union2.membership.forward with hp348casessplitwith fresh | covered349 . exact freshPairs.subset at A, B with p, fresh350 . exact coveredPairs.subset at A, B with p, covered351 . intro hp352obtain⟨bound, g, hg, b, hb, shape⟩:= product.membership.forward with hp353rw shape354have alternatives : b ∈ functionImage(g, A, B) ∨¬b ∈ functionImage(g, A, B) bytauto355cases alternatives with covered | absent356 . apply union2.right357exact coveredPairs.pair.backward with⟨hg, hb, covered⟩358 . apply union2.left359exact freshPairs.pair.backward with⟨hg, hb, absent⟩360361theorem freshPairs.finite (A B : Set)362requires finiteA : Finite(A)363requires finiteB : Finite(B)364shows Finite(freshPairs(A, B))365proof366have product := Finite.product with (injections.finite with367 finiteA, finiteB), finiteB368exact Finite.subset with product, (freshPairs.subset at A, B)369370theorem coveredPairs.finite (A B : Set)371requires finiteA : Finite(A)372requires finiteB : Finite(B)373shows Finite(coveredPairs(A, B))374proof375have product := Finite.product with (injections.finite with376 finiteA, finiteB), finiteB377exact Finite.subset with product, (coveredPairs.subset at A, B)378379-- Splitting an injection on insert(a, A) into its restriction and its380-- value at a lands exactly on the fresh pairs.381theorem injections.restrict (f A B a : Set)382requires member : f ∈ injections(insert(a, A), B)383shows restrict(f, A) ∈ injections(A, B)384proof385have injective := injections.injective with member386have restricted := restrict.injective with387 injective, (insert.subset_self at A, a)388exact injections.of_injective with restricted389390theorem injections.value_fresh (f A B a : Set)391requires fresh : ¬a ∈ A392requires member : f ∈ injections(insert(a, A), B)393shows¬f(a) ∈ functionImage(restrict(f, A), A, B)394proof395intro covered396have injective := injections.injective with member397have function := injections.function with member398have subset := insert.subset_self at A, a399obtain⟨inB, x, hx, shape⟩:= functionImage.membership.forward with covered400have step := restrict.domain_apply with function, subset, hx401rw step at shape402have equal := Injective.apply_cancel with injective, (insert.self at a, A), (subset with x, hx), shape403apply fresh404rw equal405exact hx406407theorem injections.adjoin (g A B a b : Set)408requires fresh : ¬a ∈ A409requires hg : g ∈ injections(A, B)410requires hb : b ∈ B411requires absent : ¬b ∈ functionImage(g, A, B)412shows adjoinMap(g, a, b) ∈ injections(insert(a, A), B)413proof414have injective := injections.injective with hg415have narrowed := Injective.avoid with injective, absent416have notIn : ¬b ∈ B ∖ {b} bysimp [difference.membership, singleton.membership]417have extended := adjoinMap.injective at g, A, B ∖ {b}, a, b with418 narrowed, fresh, notIn419have restored := insert.restore with hb420rw restored at extended421exact injections.of_injective with extended422423theorem injections.split_image (A B a : Set)424requires fresh : ¬a ∈ A425shows426 functionImage(functionSplit(A, B, a), injections(insert(a, A), B), functionSpace(A, B) × B) = freshPairs(A, B)427proof428have function := functionSplit.function at A, B, a429ext p430constructor431 . intro hp432obtain⟨bound, f, hf, shape⟩:= functionImage.membership.forward with hp433have inSpace := injections.subset at insert(a, A), B with f, hf434have value := functionSplit.value at A, B, a, f with inSpace435rw [shape, value]436apply freshPairs.pair.backward437have restricted := injections.restrict with hf438have inB := FunctionBetween.apply_closed with (injections.function with439 hf), (insert.self at a, A)440have absent := injections.value_fresh with fresh, hf441exact⟨restricted, inB, absent⟩442 . intro hp443obtain⟨bound, g, hg, b, hb, shape, absent⟩:= freshPairs.membership.forward with hp444have adjoined := injections.adjoin with fresh, hg, hb, absent445have gSpace := injections.subset at A, B with g, hg446have value := functionSplit.adjoin_value with fresh, gSpace, hb447apply functionImage.membership.backward448constructor449 . rw shape450exact product.pair with gSpace, hb451 . witness adjoinMap(g, a, b)452constructor453 . exact adjoined454 . rw [shape, value]455rfl456457theorem injections.insert_equipotent (A B a : Set)458requires fresh : ¬a ∈ A459shows injections(insert(a, A), B) ≃ freshPairs(A, B)460proof461have injective := functionSplit.injective at A, B, a462have function := functionSplit.function at A, B, a463have subset := injections.subset at insert(a, A), B464have restricted := restrict.injective with injective, subset465have equipotent := Equipotent.image with restricted466have sameImage := functionImage.restrict with function, subset467have image := injections.split_image at A, B, a with fresh468 rwa [sameImage, image] at equipotent469470-- The covered pairs are the pairs (g, x) of an injection and a point of471-- its domain, through (g, x) ↦ (g, g(x)).472defunique coveredPair (A B p : Set) (q ∈ injections(A, B) × B) :=473∃ g ∈ injections(A, B), ∃ x ∈ A, p = (g, x) ∧ q = (g, g(x))474requires pair : p ∈ injections(A, B) × A475proof476obtain⟨bound, g, hg, x, hx, shape⟩:= product.membership.forward with pair477have function := injections.function with hg478have value := FunctionBetween.apply_closed with function, hx479have output := product.pair with hg, value480refine⟨(g, g(x)), output, g, hg, x, hx, shape, rfl⟩481uniqueness482intros u hu first v hv second483obtain⟨g, hg, x, hx, shapeU, valueU⟩:= first484obtain⟨h, hh, y, hy, shapeV, valueV⟩:= second485have equal : (g, x) = (h, y) bycc486have coordinates := orderedPair.injective with equal487cc488489defgraph coveredMap (A B : Set) (p ∈ injections(A, B) × A) : injections(A, B) × B := coveredPair(A, B, p)490proof491have selected := coveredPair.selected with member492exact selected.left493494theorem coveredMap.pair (A B g x : Set)495requires hg : g ∈ injections(A, B)496requires hx : x ∈ A497shows coveredMap(A, B)((g, x)) = (g, g(x))498proof499have pair := product.pair at g, x, injections(A, B), A with*500have selected := coveredPair.selected with pair501obtain⟨h, hh, y, hy, shape, output⟩:= selected.right502have coordinates := orderedPair.injective with shape503have value := coveredMap.value with pair504cc505506theorem coveredMap.injective (A B : Set)507shows508 InjectiveBetween(coveredMap(A, B), injections(A, B) × A, injections(A, B) × B)509proof510have function := coveredMap.function at A, B511apply Injective.of_pointwise with function512intros p hp q hq same513obtain⟨boundP, g, hg, x, hx, shapeP⟩:= product.membership.forward with hp514obtain⟨boundQ, h, hh, y, hy, shapeQ⟩:= product.membership.forward with hq515have valueP := coveredMap.pair with hg, hx516have valueQ := coveredMap.pair with hh, hy517rw [shapeP, shapeQ, valueP, valueQ] at same518have coordinates := orderedPair.injective with same519have sameFunction := coordinates.left520have sameValue := coordinates.right521rw← sameFunction at sameValue522have injective := injections.injective with hg523have sameInput := Injective.apply_cancel with injective, hx, hy, sameValue524rw [shapeP, shapeQ, sameFunction, sameInput]525rfl526527theorem coveredMap.image (A B : Set)528shows529 functionImage(coveredMap(A, B), injections(A, B) × A, injections(A, B) × B) = coveredPairs(A, B)530proof531have function := coveredMap.function at A, B532ext q533constructor534 . intro hq535obtain⟨bound, p, hp, shape⟩:= functionImage.membership.forward with hq536obtain⟨boundP, g, hg, x, hx, shapeP⟩:= product.membership.forward with hp537have value := coveredMap.pair with hg, hx538rw [shape, shapeP, value]539apply coveredPairs.pair.backward540have gFunction := injections.function with hg541have inB := FunctionBetween.apply_closed with gFunction, hx542have covered := functionImage.value with gFunction, hx543exact⟨hg, inB, covered⟩544 . intro hq545obtain⟨bound, g, hg, b, hb, shape, covered⟩:= coveredPairs.membership.forward with hq546obtain⟨inB, x, hx, valueShape⟩:= functionImage.membership.forward with covered547have pair := product.pair at g, x, injections(A, B), A with hg, hx548have value := coveredMap.pair with hg, hx549apply functionImage.membership.backward550constructor551 . exact bound552 . witness (g, x)553constructor554 . exact pair555 . rw [shape, value, valueShape]556rfl557558theorem coveredPairs.equipotent (A B : Set)559shows injections(A, B) × A ≃ coveredPairs(A, B)560proof561have equipotent := Equipotent.image with (coveredMap.injective at A, B)562rw coveredMap.image at equipotent563exact equipotent564565-- Truncated subtraction distributes over a product.566theorem sub.self_add (a d : Nat)567shows a - (a + d) =0568proof569induction d570| zero =>571have shape : a +0= a byring572rw shape573have step := sub.add_right at0, a574have zero : 0+ a = a byring575rw zero at step576exact step577| j +1using ih =>578have shape : a + (j +1) = succ(a + j) byring579rw [shape, sub.succ_right, ih]580exact predecessor.zero581582theorem sub.vanishes_of_le (a b : Nat)583requires le : a ≤ b584shows a - b =0585proof586obtain⟨d, dNat, shape⟩:= le587rw← shape588exact sub.self_add at a, d589590theorem mul.sub_distributes (a n m : Nat)591shows a * (n - m) = a * n - a * m592proof593have alternatives := LessEqual.total at m, n594cases alternatives with le | ge595 . obtain⟨d, dNat, shape⟩:= le596rw← shape597haveleft : m + d - m = d598have commute : m + d = d + m byring599rw commute600exact sub.add_right at d, m601haveright : a * (m + d) - a * m = a * d602have expand : a * (m + d) = a * d + a * m byring603rw expand604exact sub.add_right at a * d, a * m605rw [left, right]606rfl607 . have zero := sub.vanishes_of_le with ge608have bound := LessEqual.mul_left at n, m, a with ge609have productZero := sub.vanishes_of_le with bound610rw [zero, productZero]611ring612613-- The count of injections grows by the factor n − m when the domain grows614-- by a point.615theorem injections.insert_count (A B a : Set) (m n : Nat)616requires fresh : ¬a ∈ A617requires countedA : HasCardinality(A, m)618requires countedB : HasCardinality(B, n)619requires counted : HasCardinality(injections(A, B), fallingFactorial(n, m))620shows HasCardinality(injections(insert(a, A), B), fallingFactorial(n, m +1))621proof622have finiteA := Finite.from_cardinality with countedA623have finiteB := Finite.from_cardinality with countedB624have finiteInj := Finite.from_cardinality with counted625have sizeA := cardinality.eq_of_has with countedA626have sizeB := cardinality.eq_of_has with countedB627have sizeInj := cardinality.eq_of_has with counted628have finiteFresh := freshPairs.finite with finiteA, finiteB629have finiteCovered := coveredPairs.finite with finiteA, finiteB630havesplit:= cardinality.union_disjoint with631 finiteFresh, finiteCovered, (freshPairs.disjoint at A, B)632rw freshPairs.union atsplit633have productB := cardinality.product_count with finiteInj, finiteB634have productA := cardinality.product_count with finiteInj, finiteA635have coveredCount := cardinality.equipotent with (Finite.product with636 finiteInj, finiteA), (coveredPairs.equipotent at A, B)637rw [sizeInj, sizeB] at productB638rw [sizeInj, sizeA] at productA639rw productA at coveredCount640rw [productB, ← coveredCount] atsplit641have natural := fallingFactorial.natural at n, m642have natFresh := cardinality.nat with finiteFresh643have freshCount : cardinality(freshPairs(A, B)) = fallingFactorial(n, m) * (n - m)644rw mul.sub_distributes645rwsplit646 symm647exact sub.add_right at cardinality(freshPairs(A, B)), fallingFactorial(n, m) * m648have finiteInsert := injections.finite with (Finite.insert at A, a with649 finiteA), finiteB650have same := cardinality.equipotent with finiteInsert, (injections.insert_equipotent at A, B, a with fresh)651rw [freshCount, ← fallingFactorial.succ] at same652exact HasCardinality.of_cardinality with finiteInsert, same653654-- The number of injections from an m-element set into an n-element set.655theorem injections.cardinality (m : Nat)656shows∀ A, ∀ B, ∀ n, Nat(n) → HasCardinality(A, m) → HasCardinality(B, n) →657 HasCardinality(injections(A, B), fallingFactorial(n, m))658proof659induction m660| zero =>661intros A B n nNat countedA countedB662have empty := HasCardinality.empty_of_zero at A with countedA663rw [empty, injections.empty_domain, fallingFactorial.zero]664constructor665 . exact Naturals.constructor.succ at0with Naturals.constructor.zero666 . exact Equipotent.singleton_one at∅667| k +1using ih =>668intros A B n nNat countedA countedB669have hk : k +1= succ(k) := add.right_one with*670rw hk at countedA671obtain⟨a, member⟩:= HasCardinality.exists_member with countedA672have rest := HasCardinality.remove at A, a, k with countedA, member673have fresh : ¬a ∈ A ∖ {a} bysimp [difference.membership, singleton.membership]674have restored := insert.restore with member675have restCount := ih with A ∖ {a}, B, n, nNat, rest, countedB676have inserted := injections.insert_count at A ∖ {a}, B, a, k, n with677 fresh, rest, countedB, restCount678rw restored at inserted679exact inserted680681theorem injections.count (A B : Set)682requires finiteA : Finite(A)683requires finiteB : Finite(B)684shows685 cardinality(injections(A, B)) = fallingFactorial(cardinality(B), cardinality(A))686proof687have countedA := cardinality.correct with finiteA688have countedB := cardinality.correct with finiteB689have natA := cardinality.nat with finiteA690have natB := cardinality.nat with finiteB691have all := injections.cardinality at cardinality(A)692have counted := all with A, B, cardinality(B), natB, countedA, countedB693exact cardinality.eq_of_has with counted694695theorem injections.count_self (A : Set)696requires finite : Finite(A)697shows cardinality(injections(A, A)) = cardinality(A)!698proof699have count := injections.count with finite, finite700have natA := cardinality.nat with finite701rw [count, fallingFactorial.self]702rfl703704theorem injections.empty_of_larger (A B : Set)705requires finiteB : Finite(B)706requires more : cardinality(B) < cardinality(A)707shows injections(A, B) =∅708proof709apply Subset.empty_iff.forward710intros f hf711have injective := injections.injective with hf712have function := Injective.function with injective713exfalso714exact pigeonhole.not_injective with function, finiteB, more, injective715716theorem injections.count_choose (A B : Set)717requires finiteA : Finite(A)718requires finiteB : Finite(B)719requires le : cardinality(A) ≤ cardinality(B)720shows721 cardinality(injections(A, B)) = (cardinality(B) choose cardinality(A)) * cardinality(A)!722proof723have count := injections.count with finiteA, finiteB724have natA := cardinality.nat with finiteA725have natB := cardinality.nat with finiteB726rw count727exact fallingFactorial.choose with le728729-- Bijections between two sets, as a set of function graphs.730def bijections (A B : Set) : Set:=731 { f ∈ functionSpace(A, B) | BijectiveBetween(f, A, B) }732733theorem bijections.of_bijective (f A B : Set)734requires bijective : BijectiveBetween(f, A, B)735shows f ∈ bijections(A, B)736proof737have function := Injective.function with (Bijective.injective with bijective)738have inSpace := functionSpace.mem_iff.backward with function739exact bijections.membership.backward with⟨inSpace, bijective⟩740741theorem bijections.bijective (f A B : Set)742requires member : f ∈ bijections(A, B)743shows BijectiveBetween(f, A, B)744proof745have parts := bijections.membership.forward with member746exact parts.right747748theorem bijections.subset_injections (A B : Set)749shows bijections(A, B) ⊆ injections(A, B)750proof751intros f hf752have bijective := bijections.bijective with hf753exact injections.of_injective with (Bijective.injective with bijective)754755theorem bijections.finite (A B : Set)756requires finiteA : Finite(A)757requires finiteB : Finite(B)758shows Finite(bijections(A, B))759proof760have finite := injections.finite with finiteA, finiteB761exact Finite.subset with finite, (bijections.subset_injections at A, B)762763-- Between finite sets of the same size every injection is a bijection.764theorem bijections.eq_injections (A B : Set)765requires finiteB : Finite(B)766requires same : cardinality(A) = cardinality(B)767shows bijections(A, B) = injections(A, B)768proof769apply Subset.antisymmetric with (bijections.subset_injections at A, B)770intros f hf771have injective := injections.injective with hf772have bijective := Finite.bijective_of_injective with injective, finiteB, same773exact bijections.of_bijective with bijective774775theorem bijections.count (A B : Set)776requires finiteA : Finite(A)777requires finiteB : Finite(B)778requires same : cardinality(A) = cardinality(B)779shows cardinality(bijections(A, B)) = cardinality(A)!780proof781have equal := bijections.eq_injections with finiteB, same782have count := injections.count with finiteA, finiteB783have natA := cardinality.nat with finiteA784rw [equal, count, ← same, fallingFactorial.self]785rfl786787theorem bijections.count_self (A : Set)788requires finite : Finite(A)789shows cardinality(bijections(A, A)) = cardinality(A)!790proof791have same : cardinality(A) = cardinality(A) byrfl792exact bijections.count with finite, finite, same793794theorem bijections.empty_of_ne (A B : Set)795requires finiteA : Finite(A)796requires different : cardinality(A) ≠ cardinality(B)797shows bijections(A, B) =∅798proof799apply Subset.empty_iff.forward800intros f hf801have bijective := bijections.bijective with hf802exfalso803apply different804exact cardinality.bijective with finiteA, bijective805