1-- Further identities for the binomial coefficient: the weighted row sum2-- ∑ k · (n choose k) = n · 2 ^ (n − 1), the even-index and odd-index row3-- sums agreeing at 2 ^ (n − 1), the ratio of neighbouring entries in4-- product form, unimodality of a row, and the third column5-- 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.BinomialMore11import Derangements1213-- Partial sums ∑_{i < k} i · (n choose i).14def weightedRowSum (n k : Nat) →Nat15| n, zero =>016| n, succ(k) => weightedRowSum(n, k) + k * choose(n, k)17descends k1819theorem weightedRowSum.zero (n : Nat)20shows weightedRowSum(n, 0) =021proof22simp [weightedRowSum]2324theorem weightedRowSum.succ (n k : Nat)25shows weightedRowSum(n, k +1) = weightedRowSum(n, k) + k * (n choose k)26proof27have hk : k +1= succ(k) := add.right_one with*28rw hk29simp [weightedRowSum]3031theorem weightedRowSum.natural (n k : Nat)32showsNat(weightedRowSum(n, k))33proof34induction k35| zero =>36rw weightedRowSum.zero37typecheck38| j +1using ih =>39rw weightedRowSum.succ40have cNat := choose.natural at n, j41typecheck4243theorem weightedRowSum.one (n : Nat)44shows weightedRowSum(n, 1) =045proof46have one : 0+1=1bycompute47rw← one48rw [weightedRowSum.succ, weightedRowSum.zero, choose.zero_right]49compute5051-- Absorption termwise:52-- ∑_{i ≤ k} i · (n + 1 choose i) = (n + 1) · ∑_{i < k} (n choose i).53theorem weightedRowSum.shift (n k : Nat)54shows weightedRowSum(n +1, k +1) = (n +1) * chooseRowSum(n, k)55proof56induction k57| zero =>58have one : 0+1=1bycompute59rw [one, weightedRowSum.one, chooseRowSum.zero]60ring61| j +1using ih =>62rw [weightedRowSum.succ, ih, chooseRowSum.succ]63have absorb := choose.absorption_at at n, j64have rowNat := chooseRowSum.natural at n, j65have cNat := choose.natural at n, j66have topNat := choose.natural at n +1, j +167ring [absorb]6869-- ∑_{k ≤ n + 1} k · (n + 1 choose k) = (n + 1) · 2 ^ n.70theorem weightedRowSum.full (n : Nat)71shows weightedRowSum(n +1, n +2) = (n +1) *2 ^ n72proof73have shape : n +2= (n +1) +1byring74rw [shape, weightedRowSum.shift, chooseRowSum.full]75rfl7677theorem weightedRowSum.double (n : Nat)78shows2* weightedRowSum(n, n +1) = n *2 ^ n79proof80havesplit:= natural.zero_or_successor at n81casessplitwith isZero | isSucc82 . rw isZero83compute84 . obtain⟨j, jNat, shape⟩:= isSucc85have hj : succ(j) = j +186 symm87exact add.right_one at j88have two : j +1+1= j +2byring89rw [shape, hj, two, weightedRowSum.full, pow.add_one]90have powNat := pow.closed at2, j91ring9293-- Partial sums over the even and the odd columns of a row.94def evenRowSum (n k : Nat) →Nat95| n, zero =>096| n, succ(k) => evenRowSum(n, k) + choose(n, 2* k)97descends k9899def oddRowSum (n k : Nat) →Nat100| n, zero =>0101| n, succ(k) => oddRowSum(n, k) + choose(n, 2* k +1)102descends k103104theorem evenRowSum.zero (n : Nat)105shows evenRowSum(n, 0) =0106proof107simp [evenRowSum]108109theorem evenRowSum.succ (n k : Nat)110shows evenRowSum(n, k +1) = evenRowSum(n, k) + (n choose (2* k))111proof112have hk : k +1= succ(k) := add.right_one with*113rw hk114simp [evenRowSum]115116theorem evenRowSum.natural (n k : Nat)117showsNat(evenRowSum(n, k))118proof119induction k120| zero =>121rw evenRowSum.zero122typecheck123| j +1using ih =>124rw evenRowSum.succ125have cNat := choose.natural at n, 2* j126typecheck127128theorem oddRowSum.zero (n : Nat)129shows oddRowSum(n, 0) =0130proof131simp [oddRowSum]132133theorem oddRowSum.succ (n k : Nat)134shows oddRowSum(n, k +1) = oddRowSum(n, k) + (n choose (2* k +1))135proof136have hk : k +1= succ(k) := add.right_one with*137rw hk138simp [oddRowSum]139140theorem oddRowSum.natural (n k : Nat)141showsNat(oddRowSum(n, k))142proof143induction k144| zero =>145rw oddRowSum.zero146typecheck147| j +1using ih =>148rw oddRowSum.succ149have cNat := choose.natural at n, 2* j +1150typecheck151152theorem evenRowSum.one (n : Nat)153shows evenRowSum(n, 1) =1154proof155have one : 0+1=1bycompute156rw← one157rw [evenRowSum.succ, evenRowSum.zero]158have twice : 2*0=0bycompute159rw [twice, choose.zero_right]160compute161162theorem oddRowSum.one (n : Nat)163shows oddRowSum(n, 1) = n164proof165have one : 0+1=1bycompute166rw← one167rw [oddRowSum.succ, oddRowSum.zero]168have twice : 2*0=0bycompute169rw [twice, one, choose.one_right]170ring171172-- Pascal's rule column by column: the even sums of row n + 1 come from the173-- even and the odd sums of row n.174theorem evenRowSum.pascal (n k : Nat)175shows evenRowSum(n +1, k +1) = evenRowSum(n, k +1) + oddRowSum(n, k)176proof177induction k178| zero =>179have one : 0+1=1bycompute180rw [one, evenRowSum.one, evenRowSum.one, oddRowSum.zero]181compute182| j +1using ih =>183have top := evenRowSum.succ at n +1, j +1184haveright:= evenRowSum.succ at n, j +1185have low := oddRowSum.succ at n, j186rw [top, ih, right, low]187have shape : 2* (j +1) =2* j +1+1byring188rw [shape, choose.pascal]189have aNat := evenRowSum.natural at n, j +1190have bNat := oddRowSum.natural at n, j191have cNat := choose.natural at n, 2* j +1192have dNat := choose.natural at n, 2* j +1+1193ring194195theorem oddRowSum.pascal (n k : Nat)196shows oddRowSum(n +1, k) = evenRowSum(n, k) + oddRowSum(n, k)197proof198induction k199| zero =>200rw [oddRowSum.zero, evenRowSum.zero, oddRowSum.zero]201compute202| j +1using ih =>203rw [oddRowSum.succ, ih, evenRowSum.succ, oddRowSum.succ, choose.pascal]204have aNat := evenRowSum.natural at n, j205have bNat := oddRowSum.natural at n, j206have cNat := choose.natural at n, 2* j207have dNat := choose.natural at n, 2* j +1208ring209210-- A row sum up to an even bound splits into its even and odd parts.211theorem chooseRowSum.split_parity (n k : Nat)212shows chooseRowSum(n, 2* k) = evenRowSum(n, k) + oddRowSum(n, k)213proof214induction k215| zero =>216have twice : 2*0=0bycompute217rw [twice, chooseRowSum.zero, evenRowSum.zero, oddRowSum.zero]218compute219| j +1using ih =>220have shape : 2* (j +1) = (2* j +1) +1byring221rw [shape, chooseRowSum.succ, chooseRowSum.succ, ih]222rw [evenRowSum.succ, oddRowSum.succ]223have aNat := evenRowSum.natural at n, j224have bNat := oddRowSum.natural at n, j225have cNat := choose.natural at n, 2* j226have dNat := choose.natural at n, 2* j +1227ring228229theorem evenRowSum.add_odd (n : Nat)230shows evenRowSum(n, n +1) + oddRowSum(n, n +1) =2 ^ n231proof232rw← chooseRowSum.split_parity233have shape : 2* (n +1) = n +1+ (n +1) byring234rw shape235exact chooseRowSum.beyond at n, n +1236237theorem evenRowSum.beyond (n d : Nat)238shows evenRowSum(n, n +1+ d) = evenRowSum(n, n +1)239proof240induction d241| zero =>242have shape : n +1+0= n +1byring243rw shape244rfl245| j +1using ih =>246have shape : n +1+ (j +1) = (n +1+ j) +1byring247rw [shape, evenRowSum.succ, ih]248have below : n < 2* (n +1+ j) byarith249have vanish := choose.above_diagonal with below250rw vanish251have sumNat := evenRowSum.natural at n, n +1252ring253254theorem oddRowSum.beyond (n d : Nat)255shows oddRowSum(n, n +1+ d) = oddRowSum(n, n +1)256proof257induction d258| zero =>259have shape : n +1+0= n +1byring260rw shape261rfl262| j +1using ih =>263have shape : n +1+ (j +1) = (n +1+ j) +1byring264rw [shape, oddRowSum.succ, ih]265have below : n < 2* (n +1+ j) +1byarith266have vanish := choose.above_diagonal with below267rw vanish268have sumNat := oddRowSum.natural at n, n +1269ring270271-- The even columns of row n + 1 add up to 2 ^ n, and so do the odd columns.272theorem evenRowSum.full (n : Nat)273shows evenRowSum(n +1, n +2) =2 ^ n274proof275have shape : n +2= (n +1) +1byring276rw [shape, evenRowSum.pascal]277have tail := evenRowSum.beyond at n, 1278rw tail279exact evenRowSum.add_odd at n280281theorem oddRowSum.full (n : Nat)282shows oddRowSum(n +1, n +2) =2 ^ n283proof284rw oddRowSum.pascal285have shape : n +2= n +1+1byring286rw shape287have evenTail := evenRowSum.beyond at n, 1288have oddTail := oddRowSum.beyond at n, 1289rw [evenTail, oddTail]290exact evenRowSum.add_odd at n291292-- The alternating row sum vanishes: even and odd columns balance.293theorem choose.alternating (n : Nat)294shows evenRowSum(n +1, n +2) = oddRowSum(n +1, n +2)295proof296rw [evenRowSum.full, oddRowSum.full]297rfl298299-- The complementary absorption law300-- (m − k + 1) · (m + 1 choose k) = (m + 1) · (m choose k).301theorem choose.absorption_complement (m k : Nat)302requires le : k ≤ m303shows (m - k +1) * ((m +1) choose k) = (m +1) * (m choose k)304proof305obtain⟨d, dNat, shape⟩:= le306have difference : m - k = d307rw← shape308exact sub.add_left at d, k309rw [difference, ← shape]310have first := choose.add_symmetric at d +1, k311have shapeA : k + d +1= d +1+ k byring312rw [shapeA, first]313have second := choose.add_symmetric at d, k314have shapeB : k + d = d + k byring315rw [shapeB, second]316have absorb := choose.absorption_at at d + k, d317have aNat := choose.natural at d +1+ k, d +1318have bNat := choose.natural at d + k, d319ring [absorb]320321-- Neighbouring entries of a row:322-- (k + 1) · (m + 1 choose k + 1) = (m − k + 1) · (m + 1 choose k).323theorem choose.ratio (m k : Nat)324requires le : k ≤ m325shows (k +1) * ((m +1) choose (k +1)) = (m - k +1) * ((m +1) choose k)326proof327have complement := choose.absorption_complement with le328rw [choose.absorption_at, complement]329rfl330331theorem choose.le_succ_of_below_half (m k : Nat)332requires half : 2* k ≤ m333shows (m +1) choose k ≤ (m +1) choose (k +1)334proof335have le : k ≤ m byarith336have ratio := choose.ratio with le337have subNat := sub.closed at m, k338have cancel := sub.add_cancel_left with le339have coefficient : k +1≤ m - k +1byarith340have aNat := choose.natural at m +1, k341have bNat := choose.natural at m +1, k +1342have scaled := LessEqual.mul_right at k +1, m - k +1, (m +1) choose k343with coefficient344rw← ratio at scaled345have positive : 0 < k +1byarith346have nonzero := Less.ne_zero_of_positive with positive347exact LessEqual.mul_left_cancel_positive with nonzero, scaled348349theorem choose.lt_succ_of_below_half (m k : Nat)350requires half : 2* k +1≤ m351shows (m +1) choose k < (m +1) choose (k +1)352proof353have le : k ≤ m byarith354have ratio := choose.ratio with le355have subNat := sub.closed at m, k356have cancel := sub.add_cancel_left with le357have coefficient : k +1 < m - k +1byarith358have aNat := choose.natural at m +1, k359have bNat := choose.natural at m +1, k +1360have leTop : k ≤ m +1byarith361have positive := choose.positive with leTop362have nonzero := Less.ne_zero_of_positive with positive363have scaled := Less.mul_right at k +1, m - k +1, (m +1) choose k364with nonzero, coefficient365rw← ratio at scaled366have gapPositive : 0 < k +1byarith367have gap := Less.ne_zero_of_positive with gapPositive368exact Less.mul_left_cancel_positive with gap, scaled369370-- A row of Pascal's triangle increases up to its middle.371theorem choose.monotone_to_half (n j d : Nat)372requires half : 2* (j + d) ≤ n373shows n choose j ≤ n choose (j + d)374proof375induction d376| zero =>377intro half378have shape : j +0= j byring379rw shape380have cNat := choose.natural at n, j381exact LessEqual.reflexive at n choose j382| k +1using ih =>383intro half384have earlier : 2* (j + k) ≤ n byarith385have inner := ih with earlier386have positive : 0 < n byarith387obtain⟨m, mNat, shape⟩:= Less.exists_add_one with positive388have form : n = m +1389rw shape390ring391rw form at inner392rw form at half393rw form394have below : 2* (j + k) ≤ m byarith395have step := choose.le_succ_of_below_half at m, j + k with below396have shapeD : j + (k +1) = j + k +1byring397rw shapeD398have aNat := choose.natural at m +1, j399have bNat := choose.natural at m +1, j + k400have cNat := choose.natural at m +1, j + k +1401exact LessEqual.transitive with inner, step402403theorem choose.central_dominates_below (n k : Nat)404requires le : k ≤ n405shows (2* n) choose k ≤ (2* n) choose n406proof407obtain⟨d, dNat, shape⟩:= le408have half : 2* (k + d) ≤2* n409rw shape410have doubleNat : Nat(2* n) bytypecheck411exact LessEqual.reflexive at2* n412have bound := choose.monotone_to_half at2* n, k, d with half413rw shape at bound414exact bound415416-- The central entry dominates every entry of an even row.417theorem choose.le_central (n k : Nat)418shows (2* n) choose k ≤ (2* n) choose n419proof420have alternatives := Less.or_LessEqual at n, k421cases alternatives with above | le422 . havesplit:= Less.or_LessEqual at2* n, k423casessplitwith far | inRow424 . have vanish := choose.above_diagonal with far425rw vanish426have cNat := choose.natural at2* n, n427arith428 . have mirror := choose.symmetric at2* n, k with inRow429rw mirror430have subNat := sub.closed at2* n, k431have iff := sub.le_iff at2* n, k, n432have small : 2* n ≤ k + n byarith433have le := iff.backward with small434exact choose.central_dominates_below with le435 . exact choose.central_dominates_below with le436437theorem choose.odd_dominates_below (n k : Nat)438requires le : k ≤ n439shows (2* n +1) choose k ≤ (2* n +1) choose n440proof441obtain⟨d, dNat, shape⟩:= le442have half : 2* (k + d) ≤2* n +1443rw shape444arith445have bound := choose.monotone_to_half at2* n +1, k, d with half446rw shape at bound447exact bound448449-- The two middle entries dominate every entry of an odd row.450theorem choose.le_central_odd (n k : Nat)451shows (2* n +1) choose k ≤ (2* n +1) choose n452proof453have alternatives := Less.or_LessEqual at n, k454cases alternatives with above | le455 . havesplit:= Less.or_LessEqual at2* n +1, k456casessplitwith far | inRow457 . have vanish := choose.above_diagonal with far458rw vanish459have cNat := choose.natural at2* n +1, n460arith461 . have mirror := choose.symmetric at2* n +1, k with inRow462rw mirror463have subNat := sub.closed at2* n +1, k464have iff := sub.le_iff at2* n +1, k, n465have small : 2* n +1≤ k + n byarith466have le := iff.backward with small467exact choose.odd_dominates_below with le468 . exact choose.odd_dominates_below with le469470theorem choose.pascal_le_left (n k : Nat)471shows n choose k ≤ (n +1) choose (k +1)472proof473rw choose.pascal474have aNat := choose.natural at n, k475have bNat := choose.natural at n, k +1476arith477478theorem choose.pascal_le_right (n k : Nat)479shows n choose (k +1) ≤ (n +1) choose (k +1)480proof481rw choose.pascal482have aNat := choose.natural at n, k483have bNat := choose.natural at n, k +1484arith485486-- The third column: 6 · (n + 3 choose 3) = (n + 3)(n + 2)(n + 1).487theorem choose.three (n : Nat)488shows6* ((n +3) choose 3) = (n +3) * (n +2) * (n +1)489proof490have absorb := choose.absorption_at at n +2, 2491have three : 2+1=3bycompute492have shape : n +2+1= n +3byring493rw [three, shape] at absorb494have second := choose.two at n +1495have shape2 : n +1+1= n +2byring496rw shape2 at second497have aNat := choose.natural at n +3, 3498have bNat := choose.natural at n +2, 2499ring [absorb, second]500