1-- Bounds and divisibility for the falling factorial: it is at most n ^ m,2-- vanishes exactly above the diagonal, is a multiple of m!, splits at an3-- intermediate stage as a product of two falling factorials, divides n!,4-- and grows with its first argument5-- Part of Cumulus, the Grace17 mathematics library.6-- Copyright (c) 2026 Grant Passmore.7-- Released under the Apache License 2.0. See LICENSE in the repository root.8-- Authors: Grant Passmore910module Grace.Cumulus.Combinatorics.FallingBounds11import Catalan1213theorem fallingFactorial.le_pow (n m : Nat)14shows fallingFactorial(n, m) ≤ n ^ m15proof16induction m17| zero =>18rw [fallingFactorial.zero, pow.zero]19exact LessEqual.reflexive at120| j +1using ih =>21rw [fallingFactorial.succ, pow.succ_right]22have factor := sub.le_self at n, j23have natural := fallingFactorial.natural at n, j24have powNat := pow.closed at n, j25have subNat := sub.closed at n, j26exact LessEqual.mul with ih, factor2728theorem fallingFactorial.positive (n m : Nat)29requires le : m ≤ n30shows0 < fallingFactorial(n, m)31proof32have form := fallingFactorial.choose with le33rw form34have first := choose.positive with le35have second := factorial.positive at m36have cNat := choose.natural at n, m37have closed := factorial.closed at m38exact Less.mul_positive with first, second3940theorem fallingFactorial.eq_zero_iff (n m : Nat)41shows fallingFactorial(n, m) =0↔ n < m42proof43constructor44 . intro zero45by_contra notBelow46have le := LessEqual.of_not_Less with notBelow47have positive := fallingFactorial.positive with le48rw zero at positive49exact Less.irreflexive at0with positive50 . intro below51exact fallingFactorial.of_Less with below5253theorem fallingFactorial.ne_zero_iff (n m : Nat)54shows fallingFactorial(n, m) ≠0↔ m ≤ n55proof56constructor57 . intro nonzero58by_contra notLe59have below := Less.of_not_LessEqual with notLe60exact nonzero with (fallingFactorial.of_Less with below)61 . intro le62intro zero63have positive := fallingFactorial.positive with le64rw zero at positive65exact Less.irreflexive at0with positive6667theorem fallingFactorial.positive_iff (n m : Nat)68shows0 < fallingFactorial(n, m) ↔ m ≤ n69proof70constructor71 . intro positive72have natural := fallingFactorial.natural at n, m73have nonzero := Less.ne_zero_of_positive with positive74have iff := fallingFactorial.ne_zero_iff at n, m75exact iff.forward with nonzero76 . intro le77exact fallingFactorial.positive with le7879-- The factorial form holds without restriction: above the diagonal both80-- sides vanish.81theorem fallingFactorial.choose_mul (n k : Nat)82shows fallingFactorial(n, k) = (n choose k) * k!83proof84have alternatives := Less.or_LessEqual at n, k85cases alternatives with below | le86 . have vanish := fallingFactorial.of_Less with below87have vanishChoose := choose.above_diagonal with below88rw [vanish, vanishChoose]89have closed := factorial.closed at k90ring91 . exact fallingFactorial.choose with le9293theorem choose.mul_factorial (n k : Nat)94shows (n choose k) * k! = fallingFactorial(n, k)95proof96 symm97exact fallingFactorial.choose_mul at n, k9899theorem fallingFactorial.factorial_divides (n m : Nat)100shows m! ∣ fallingFactorial(n, m)101proof102rw fallingFactorial.choose_mul103have cNat := choose.natural at n, m104have closed := factorial.closed at m105witness n choose m106ring107108-- Splitting the falling factorial at an intermediate stage.109theorem fallingFactorial.add (n m k : Nat)110shows fallingFactorial(n, m + k) =111 fallingFactorial(n, m) * fallingFactorial(n - m, k)112proof113induction k114| zero =>115have shape : m +0= m byring116rw [shape, fallingFactorial.zero]117have natural := fallingFactorial.natural at n, m118ring119| j +1using ih =>120have shape : m + (j +1) = (m + j) +1byring121rw [shape, fallingFactorial.succ, ih, fallingFactorial.succ, sub.sub]122have natural := fallingFactorial.natural at n, m123have subNat := sub.closed at n, m124have inner := fallingFactorial.natural at n - m, j125have subNatJ := sub.closed at n - m, j126ring127128theorem fallingFactorial.divides_add (n m k : Nat)129shows fallingFactorial(n, m) ∣ fallingFactorial(n, m + k)130proof131rw fallingFactorial.add132have subNat := sub.closed at n, m133have inner := fallingFactorial.natural at n - m, k134have natural := fallingFactorial.natural at n, m135witness fallingFactorial(n - m, k)136rfl137138theorem fallingFactorial.divides_of_le (n m k : Nat)139requires le : m ≤ k140shows fallingFactorial(n, m) ∣ fallingFactorial(n, k)141proof142obtain⟨d, dNat, shape⟩:= le143rw← shape144exact fallingFactorial.divides_add at n, m, d145146-- fallingFactorial(n, m) · (n − m)! = n! below the diagonal.147theorem fallingFactorial.mul_factorial_sub (n m : Nat)148requires le : m ≤ n149shows fallingFactorial(n, m) * (n - m)! = n!150proof151obtain⟨d, dNat, shape⟩:= le152have difference : n - m = d153rw← shape154exact sub.add_left at d, m155rw [difference, ← shape]156have row := fallingFactorial.mul_factorial at m157exact row with d, dNat158159theorem fallingFactorial.divides_factorial (n m : Nat)160requires le : m ≤ n161shows fallingFactorial(n, m) ∣ n!162proof163have form := fallingFactorial.mul_factorial_sub with le164rw← form165have subNat := sub.closed at n, m166have closed := factorial.closed at n - m167have natural := fallingFactorial.natural at n, m168witness (n - m)!169rfl170171theorem fallingFactorial.le_factorial (n m : Nat)172requires le : m ≤ n173shows fallingFactorial(n, m) ≤ n!174proof175have divides := fallingFactorial.divides_factorial with le176have nonzero := factorial.nonzero at n177have natural := fallingFactorial.natural at n, m178have closed := factorial.closed at n179exact divides.le with divides, nonzero180181theorem fallingFactorial.two (n : Nat)182shows fallingFactorial(n, 2) = n * (n - 1)183proof184have two : 1+1=2bycompute185rw← two186rw [fallingFactorial.succ, fallingFactorial.one]187rfl188189-- The falling factorial grows with its first argument.190theorem fallingFactorial.le_succ_left (n m : Nat)191shows fallingFactorial(n, m) ≤ fallingFactorial(n +1, m)192proof193havesplit:= natural.zero_or_successor at m194casessplitwith isZero | isSucc195 . rw [isZero, fallingFactorial.zero, fallingFactorial.zero]196exact LessEqual.reflexive at1197 . obtain⟨j, jNat, shape⟩:= isSucc198have hj : succ(j) = j +1199 symm200exact add.right_one at j201rw [shape, hj, fallingFactorial.succ, fallingFactorial.succ_succ]202have natural := fallingFactorial.natural at n, j203have subNat := sub.closed at n, j204have factor : n - j ≤ n +1205haveself:= sub.le_self at n, j206arith207have scaled := LessEqual.mul_left at n - j, n +1, fallingFactorial(n, j)208with factor209have commute : (n +1) * fallingFactorial(n, j) =210 fallingFactorial(n, j) * (n +1) byring211rw commute212exact scaled213214theorem fallingFactorial.le_add_left (n d m : Nat)215shows fallingFactorial(n, m) ≤ fallingFactorial(n + d, m)216proof217induction d218| zero =>219have shape : n +0= n byring220rw shape221have natural := fallingFactorial.natural at n, m222exact LessEqual.reflexive at fallingFactorial(n, m)223| j +1using ih =>224have shape : n + (j +1) = (n + j) +1byring225rw shape226have step := fallingFactorial.le_succ_left at n + j, m227have aNat := fallingFactorial.natural at n, m228have bNat := fallingFactorial.natural at n + j, m229have cNat := fallingFactorial.natural at n + j +1, m230exact LessEqual.transitive with ih, step231232theorem fallingFactorial.monotone_left (n k m : Nat)233requires le : n ≤ k234shows fallingFactorial(n, m) ≤ fallingFactorial(k, m)235proof236obtain⟨d, dNat, shape⟩:= le237rw← shape238exact fallingFactorial.le_add_left at n, d, m239240-- The binomial coefficient is bounded by the power n ^ k.241theorem choose.le_pow_base (n k : Nat)242shows n choose k ≤ n ^ k243proof244have cNat := choose.natural at n, k245have closed := factorial.closed at k246have nonzero := factorial.nonzero at k247have grow := LessEqual.le_mul_right at n choose k, k! with nonzero248rw choose.mul_factorial at grow249have bound := fallingFactorial.le_pow at n, k250have natural := fallingFactorial.natural at n, k251have powNat := pow.closed at n, k252exact LessEqual.transitive with grow, bound253254-- There are no more injections than functions.255theorem injections.count_le (A B : Set)256requires finiteA : Finite(A)257requires finiteB : Finite(B)258shows cardinality(injections(A, B)) ≤ cardinality(functionSpace(A, B))259proof260haveleft:= injections.count with finiteA, finiteB261haveright:= functionSpace.count with finiteA, finiteB262rw [left, right]263have aNat := cardinality.nat with finiteA264have bNat := cardinality.nat with finiteB265exact fallingFactorial.le_pow at cardinality(B), cardinality(A)266