Skip to content

Commit 8f463bc

Browse files
committed
feat: Define general binomial coefficients (Ring.choose) (#9719)
We define generalized binomial coefficients, and prove a couple basic properties. In particular, we show that multiplication by a suitable factorial yields a descending Pochhammer evaluation. We also show that casting `Nat.choose` is the same as taking `Ring.choose` of a natural number cast. To prove these, we add some results about polynomial evaluation.
1 parent 103d8a1 commit 8f463bc

File tree

4 files changed

+89
-25
lines changed

4 files changed

+89
-25
lines changed

Mathlib/Data/Nat/Factorial/SuperFactorial.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ private theorem matrixOf_eval_descPochhammer_eq_mul_matrixOf_choose {n : ℕ} (v
106106
(∏ i : Fin n, Nat.factorial i) *
107107
(Matrix.of (fun (i j : Fin n) => (Nat.choose (v i) (j : ℕ) : ℤ))).det := by
108108
convert Matrix.det_mul_row (fun (i : Fin n) => ((Nat.factorial (i : ℕ)):ℤ)) _
109-
· rw [Matrix.of_apply, descPochhammer_int_eq_descFactorial _ _]
109+
· rw [Matrix.of_apply, descPochhammer_eval_eq_descFactorial ℤ _ _]
110110
congr
111111
exact Nat.descFactorial_eq_factorial_mul_choose _ _
112112
· rw [Nat.cast_prod]

Mathlib/Data/Polynomial/Eval.lean

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,31 @@ theorem iterate_comp_eval₂ (k : ℕ) (t : S) :
10711071

10721072
end
10731073

1074+
section Algebra
1075+
1076+
variable [CommSemiring R] [Semiring S] [Algebra R S] (x : S) (p q : R[X])
1077+
1078+
@[simp]
1079+
theorem eval₂_mul' :
1080+
(p * q).eval₂ (algebraMap R S) x = p.eval₂ (algebraMap R S) x * q.eval₂ (algebraMap R S) x := by
1081+
exact eval₂_mul_noncomm _ _ fun k => Algebra.commute_algebraMap_left (coeff q k) x
1082+
1083+
@[simp]
1084+
theorem eval₂_pow' (n : ℕ) :
1085+
(p ^ n).eval₂ (algebraMap R S) x = (p.eval₂ (algebraMap R S) x) ^ n := by
1086+
induction n with
1087+
| zero => simp only [Nat.zero_eq, pow_zero, eval₂_one]
1088+
| succ n ih => rw [pow_succ, pow_succ, eval₂_mul', ih]
1089+
1090+
@[simp]
1091+
theorem eval₂_comp' : eval₂ (algebraMap R S) x (p.comp q) =
1092+
eval₂ (algebraMap R S) (eval₂ (algebraMap R S) x q) p := by
1093+
induction p using Polynomial.induction_on' with
1094+
| h_add r s hr hs => simp only [add_comp, eval₂_add, hr, hs]
1095+
| h_monomial n a => simp only [monomial_comp, eval₂_mul', eval₂_C, eval₂_monomial, eval₂_pow']
1096+
1097+
end Algebra
1098+
10741099
section
10751100

10761101
variable [CommSemiring R] {p q : R[X]} {x : R} [CommSemiring S] (f : R →+* S)

Mathlib/RingTheory/Binomial.lean

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,14 @@ Pochhammer polynomial `X(X+1)⋯(X+(k-1))` at any element is divisible by `k!`.
3030
## TODO
3131
3232
* Replace `Nat.multichoose` with `Ring.multichoose`.
33-
* `Ring.choose` for binomial rings.
34-
* Generalize to the power-associative case, when power-associativity is implemented.
33+
* Generalize from `Semiring` to `AddCommMonoid` with `Pow R ℕ` using `smeval`.
3534
3635
-/
3736

3837
open Function
3938

39+
section Multichoose
40+
4041
/-- A binomial ring is a ring for which ascending Pochhammer evaluations are uniquely divisible by
4142
suitable factorials. We define this notion for semirings, but retain the ring name. We introduce
4243
`Ring.multichoose` as the uniquely defined quotient. -/
@@ -49,8 +50,6 @@ class BinomialRing (R : Type*) [Semiring R] where
4950
factorial_nsmul_multichoose (r : R) (n : ℕ) :
5051
n.factorial • multichoose r n = Polynomial.eval r (ascPochhammer R n)
5152

52-
section Binomial
53-
5453
namespace Ring
5554

5655
variable {R : Type*} [Semiring R] [BinomialRing R]
@@ -67,7 +66,7 @@ def multichoose (r : R) (n : ℕ) : R := BinomialRing.multichoose r n
6766
theorem multichoose_eq_multichoose (r : R) (n : ℕ) :
6867
BinomialRing.multichoose r n = multichoose r n := rfl
6968

70-
theorem factorial_nsmul_multichoose_eq_eval_ascPochhammer (r : R) (n : ℕ) :
69+
theorem factorial_nsmul_multichoose_eq_ascPochhammer (r : R) (n : ℕ) :
7170
n.factorial • multichoose r n = Polynomial.eval r (ascPochhammer R n) :=
7271
BinomialRing.factorial_nsmul_multichoose r n
7372

@@ -78,7 +77,7 @@ instance Nat.instBinomialRing : BinomialRing ℕ where
7877
multichoose := Nat.multichoose
7978
factorial_nsmul_multichoose r n := by
8079
rw [Nat.multichoose_eq, smul_eq_mul, ← Nat.descFactorial_eq_factorial_mul_choose,
81-
ascPochhammer_nat_eq_descFactorial]
80+
ascPochhammer_nat_eq_descFactorial]
8281

8382
/-- The multichoose function for integers. -/
8483
def Int.multichoose (n : ℤ) (k : ℕ) : ℤ :=
@@ -98,7 +97,31 @@ instance Int.instBinomialRing : BinomialRing ℤ where
9897
ascPochhammer_eval_cast]
9998
| negSucc n =>
10099
rw [mul_comm, mul_assoc, ← Nat.cast_mul, mul_comm _ (k.factorial),
101-
← Nat.descFactorial_eq_factorial_mul_choose, ← descPochhammer_int_eq_descFactorial,
100+
← Nat.descFactorial_eq_factorial_mul_choose, ← descPochhammer_eval_eq_descFactorial,
102101
← Int.neg_ofNat_succ, ascPochhammer_eval_neg_eq_descPochhammer]
103102

104-
end Binomial
103+
end Multichoose
104+
105+
section Choose
106+
107+
namespace Ring
108+
109+
variable {R : Type*} [Ring R] [BinomialRing R]
110+
111+
/-- The binomial coefficient `choose r n` generalizes the natural number `choose` function,
112+
interpreted in terms of choosing without replacement. -/
113+
def choose (r : R) (n : ℕ): R := multichoose (r - n + 1) n
114+
115+
theorem descPochhammer_eq_factorial_smul_choose (r : R) (n : ℕ) :
116+
Polynomial.eval r (descPochhammer R n) = n.factorial • choose r n := by
117+
rw [choose, factorial_nsmul_multichoose_eq_ascPochhammer, descPochhammer_eval_eq_ascPochhammer]
118+
119+
theorem choose_nat_cast (n k : ℕ) : choose (n : R) k = Nat.choose n k := by
120+
refine nsmul_right_injective (Nat.factorial k) (Nat.factorial_ne_zero k) ?_
121+
simp only
122+
rw [← descPochhammer_eq_factorial_smul_choose, nsmul_eq_mul, ← Nat.cast_mul,
123+
← Nat.descFactorial_eq_factorial_mul_choose, ← descPochhammer_eval_eq_descFactorial]
124+
125+
end Ring
126+
127+
end Choose

Mathlib/RingTheory/Polynomial/Pochhammer.lean

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,17 @@ theorem ascPochhammer_map (f : S →+* T) (n : ℕ) :
8787
· simp [ih, ascPochhammer_succ_left, map_comp]
8888
#align pochhammer_map ascPochhammer_map
8989

90+
theorem ascPochhammer_eval₂ (f : S →+* T) (n : ℕ) (t : T) :
91+
(ascPochhammer T n).eval t = (ascPochhammer S n).eval₂ f t := by
92+
rw [← ascPochhammer_map f]
93+
exact eval_map f t
94+
95+
theorem ascPochhammer_eval_comp {R : Type*} [CommSemiring R] (n : ℕ) (p : R[X]) [Algebra R S]
96+
(x : S) : ((ascPochhammer S n).comp (p.map (algebraMap R S))).eval x =
97+
(ascPochhammer S n).eval (p.eval₂ (algebraMap R S) x) := by
98+
rw [ascPochhammer_eval₂ (algebraMap R S), ← eval₂_comp', ← ascPochhammer_map (algebraMap R S),
99+
← map_comp, eval_map]
100+
90101
end
91102

92103
@[simp, norm_cast]
@@ -328,6 +339,16 @@ theorem descPochhammer_succ_comp_X_sub_one (n : ℕ) :
328339
rw [← sub_mul, descPochhammer_succ_right ℤ n, mul_comp, mul_comm, sub_comp, X_comp, nat_cast_comp]
329340
ring
330341

342+
theorem descPochhammer_eval_eq_ascPochhammer (r : R) (n : ℕ) :
343+
(descPochhammer R n).eval r = (ascPochhammer R n).eval (r - n + 1) := by
344+
induction n with
345+
| zero => rw [descPochhammer_zero, eval_one, ascPochhammer_zero, eval_one]
346+
| succ n ih =>
347+
rw [Nat.cast_succ, sub_add, add_sub_cancel, descPochhammer_succ_eval, ih,
348+
ascPochhammer_succ_left, X_mul, eval_mul_X, show (X + 1 : R[X]) =
349+
(X + 1 : ℕ[X]).map (algebraMap ℕ R) by simp only [Polynomial.map_add, map_X,
350+
Polynomial.map_one], ascPochhammer_eval_comp, eval₂_add, eval₂_X, eval₂_one]
351+
331352
theorem descPochhammer_mul (n m : ℕ) :
332353
descPochhammer R n * (descPochhammer R m).comp (X - (n : R[X])) = descPochhammer R (n + m) := by
333354
induction' m with m ih
@@ -347,25 +368,20 @@ theorem ascPochhammer_eval_neg_eq_descPochhammer (r : R) : ∀ (k : ℕ),
347368
pow_add, pow_one, mul_assoc ((-1)^k) (-1), mul_sub, neg_one_mul, neg_mul_eq_mul_neg,
348369
Nat.cast_comm, sub_eq_add_neg, neg_one_mul, neg_neg, ← mul_add]
349370

350-
theorem descPochhammer_int_eq_descFactorial (n : ℕ) :
351-
∀ k, (descPochhammer ℤ k).eval (n : ℤ) = n.descFactorial k
352-
| 0 => by
353-
rw [descPochhammer_zero, eval_one, Nat.descFactorial_zero]
354-
rfl
355-
| t + 1 => by
356-
rw [descPochhammer_succ_right, eval_mul, descPochhammer_int_eq_descFactorial n t]
357-
simp only [eval_sub, eval_X, eval_nat_cast, Nat.descFactorial_succ, Nat.cast_mul,
358-
Nat.descFactorial_eq_zero_iff_lt]
359-
rw [mul_comm]
360-
simp only [mul_eq_mul_right_iff, Nat.cast_eq_zero, Nat.descFactorial_eq_zero_iff_lt]
361-
by_cases h : n < t
362-
· tauto
363-
· left
364-
exact (Int.ofNat_sub <| not_lt.mp h).symm
371+
theorem descPochhammer_eval_eq_descFactorial (n k : ℕ) :
372+
(descPochhammer R k).eval (n : R) = n.descFactorial k := by
373+
induction k with
374+
| zero => rw [descPochhammer_zero, eval_one, Nat.descFactorial_zero, Nat.cast_one]
375+
| succ k ih =>
376+
rw [descPochhammer_succ_right, Nat.descFactorial_succ, mul_sub, eval_sub, eval_mul_X,
377+
← Nat.cast_comm k, eval_nat_cast_mul, ← Nat.cast_comm n, ← sub_mul, ih]
378+
by_cases h : n < k
379+
rw [Nat.descFactorial_eq_zero_iff_lt.mpr h, Nat.cast_zero, mul_zero, mul_zero, Nat.cast_zero]
380+
rw [Nat.cast_mul, Nat.cast_sub <| not_lt.mp h]
365381

366382
theorem descPochhammer_int_eq_ascFactorial (a b : ℕ) :
367383
(descPochhammer ℤ b).eval (a + b : ℤ) = (a + 1).ascFactorial b := by
368-
rw [← Nat.cast_add, descPochhammer_int_eq_descFactorial (a + b) b,
384+
rw [← Nat.cast_add, descPochhammer_eval_eq_descFactorial ℤ (a + b) b,
369385
Nat.add_descFactorial_eq_ascFactorial]
370386

371387
end Ring

0 commit comments

Comments
 (0)