|
| 1 | +import RealRooted.ParkingFunctions.Descents.Basic |
| 2 | +import RealRooted.ThresholdMatrix |
| 3 | + |
| 4 | +/-! |
| 5 | +# All-word descent polynomials |
| 6 | +
|
| 7 | +This is the all-word side of the Diaconis--Hicks parking-function descent |
| 8 | +identity. It uses a last-letter refinement and the checked |
| 9 | +Haglund--Zhang threshold-matrix theorem to prove splitness of the recursively |
| 10 | +defined word polynomial. Identifying that polynomial with the literal finite |
| 11 | +sum over words, and transferring it to parking functions, remain separate |
| 12 | +combinatorial work. |
| 13 | +
|
| 14 | +This module is extracted from the checked all-word A333829 development in |
| 15 | +`sqrt-of-2/real-rooted-oeis-proofs` PR #123. |
| 16 | +-/ |
| 17 | + |
| 18 | +open Polynomial |
| 19 | + |
| 20 | +namespace RealRooted.ParkingFunctions |
| 21 | + |
| 22 | +noncomputable section |
| 23 | + |
| 24 | +open RealRooted.OEIS.Backend |
| 25 | + |
| 26 | +/-- Threshold rows for the reversed-last-letter word recursion. -/ |
| 27 | +def wordDescentRows (m : ℕ) : List (ℕ × ℝ[X]) := |
| 28 | + (List.range m).map fun j => (j, (1 : ℝ[X])) |
| 29 | + |
| 30 | +@[simp] |
| 31 | +theorem length_wordDescentRows (m : ℕ) : (wordDescentRows m).length = m := by |
| 32 | + simp [wordDescentRows] |
| 33 | + |
| 34 | +@[simp] |
| 35 | +theorem get_wordDescentRows_fst (m : ℕ) (i : Fin (wordDescentRows m).length) : |
| 36 | + ((wordDescentRows m).get i).1 = i.1 := by |
| 37 | + simp only [wordDescentRows, List.get_eq_getElem, List.getElem_map] |
| 38 | + grind |
| 39 | + |
| 40 | +private theorem wordDescentRows_data (m : ℕ) : HZData (wordDescentRows m) := by |
| 41 | + constructor |
| 42 | + · intro p hp |
| 43 | + simp only [wordDescentRows, List.mem_map] at hp |
| 44 | + obtain ⟨j, _, rfl⟩ := hp |
| 45 | + exact Or.inl rfl |
| 46 | + · intro i j hij |
| 47 | + rw [get_wordDescentRows_fst, get_wordDescentRows_fst] |
| 48 | + exact hij |
| 49 | + · intro i j _ _ h |
| 50 | + simp [wordDescentRows, List.get_eq_getElem, List.getElem_map] at h |
| 51 | + |
| 52 | +/-- Last-letter-refined descent enumerators for nonempty words on an alphabet |
| 53 | +of size `m`, with terminal letters in reverse order. -/ |
| 54 | +def wordDescentRefined (m : ℕ) : ℕ → List ℝ[X] |
| 55 | + | 0 => List.replicate m 1 |
| 56 | + | r + 1 => matPolyAction (hzMatrix m (wordDescentRows m)) (wordDescentRefined m r) |
| 57 | + |
| 58 | +@[simp] |
| 59 | +theorem length_wordDescentRefined (m r : ℕ) : |
| 60 | + (wordDescentRefined m r).length = m := by |
| 61 | + induction r with |
| 62 | + | zero => simp [wordDescentRefined] |
| 63 | + | succ r => simp [wordDescentRefined] |
| 64 | + |
| 65 | +private theorem replicate_one_zipWith_sum (fs : List ℝ[X]) : |
| 66 | + ((List.replicate fs.length 1).zipWith (· * ·) fs).sum = fs.sum := by |
| 67 | + induction fs with |
| 68 | + | nil => simp |
| 69 | + | cons f fs ih => |
| 70 | + simp only [List.length_cons, List.replicate_succ, |
| 71 | + List.zipWith_cons_cons, one_mul, List.sum_cons] |
| 72 | + simp_all |
| 73 | + |
| 74 | +private theorem thresholdRow_zero_one (q : ℕ) : |
| 75 | + thresholdRow q 0 (1 : ℝ[X]) = List.replicate q 1 := by |
| 76 | + apply List.ext_get |
| 77 | + · simp |
| 78 | + · intro i hi₁ hi₂ |
| 79 | + rw [show (thresholdRow q 0 (1 : ℝ[X])).get ⟨i, hi₁⟩ = |
| 80 | + thresholdEntry 0 1 i by exact get_thresholdRow ⟨i, hi₁⟩] |
| 81 | + simp [thresholdEntry] |
| 82 | + |
| 83 | +private theorem thresholdRow_succ (q t : ℕ) : |
| 84 | + thresholdRow (q + 1) (t + 1) (1 : ℝ[X]) = |
| 85 | + X :: thresholdRow q t 1 := by |
| 86 | + apply List.ext_get |
| 87 | + · simp |
| 88 | + · intro i hi₁ hi₂ |
| 89 | + rw [show (thresholdRow (q + 1) (t + 1) (1 : ℝ[X])).get ⟨i, hi₁⟩ = |
| 90 | + thresholdEntry (t + 1) 1 i by exact get_thresholdRow ⟨i, hi₁⟩] |
| 91 | + cases i with |
| 92 | + | zero => simp [thresholdEntry] |
| 93 | + | succ i => |
| 94 | + rw [show (X :: thresholdRow q t (1 : ℝ[X])).get ⟨i + 1, hi₂⟩ = |
| 95 | + (thresholdRow q t 1).get ⟨i, by grind⟩ by simp] |
| 96 | + rw [show (thresholdRow q t (1 : ℝ[X])).get ⟨i, by grind⟩ = |
| 97 | + thresholdEntry t 1 i by exact get_thresholdRow ⟨i, by grind⟩] |
| 98 | + rcases lt_trichotomy i t with hit | hit | hit |
| 99 | + · have hs : i + 1 < t + 1 := by lia |
| 100 | + simp [thresholdEntry, hit, hs] |
| 101 | + · simp_all |
| 102 | + · simp [thresholdEntry] |
| 103 | + |
| 104 | +private theorem zipWith_thresholdRow_one_sum (fs : List ℝ[X]) (t : ℕ) : |
| 105 | + ((thresholdRow fs.length t 1).zipWith (· * ·) fs).sum = |
| 106 | + staircaseSum fs t := by |
| 107 | + induction fs generalizing t with |
| 108 | + | nil => simp [staircaseSum, thresholdRow] |
| 109 | + | cons f fs ih => |
| 110 | + cases t with |
| 111 | + | zero => |
| 112 | + rw [thresholdRow_zero_one] |
| 113 | + simp only [List.length_cons] |
| 114 | + rw [List.replicate_succ, List.zipWith_cons_cons, List.sum_cons, |
| 115 | + one_mul, replicate_one_zipWith_sum] |
| 116 | + simp |
| 117 | + | succ t => |
| 118 | + rw [List.length_cons, thresholdRow_succ] |
| 119 | + simp only [List.zipWith_cons_cons, List.sum_cons] |
| 120 | + rw [ih] |
| 121 | + simp [staircaseSum] |
| 122 | + ring |
| 123 | + |
| 124 | +/-- The matrix definition unfolds to the expected last-letter recurrence. -/ |
| 125 | +theorem wordDescentRefined_succ_get (m r : ℕ) (i : Fin m) : |
| 126 | + (wordDescentRefined m (r + 1))[i.1]'(by simp) = |
| 127 | + staircaseSum (wordDescentRefined m r) i.1 := by |
| 128 | + change |
| 129 | + (matPolyAction (hzMatrix m (wordDescentRows m)) |
| 130 | + (wordDescentRefined m r))[i.1]'_ = staircaseSum (wordDescentRefined m r) i.1 |
| 131 | + simp only [matPolyAction, hzMatrix, thresholdMatrix, wordDescentRows, List.map_map, |
| 132 | + List.getElem_map, List.getElem_range, Function.comp_apply] |
| 133 | + simpa only [length_wordDescentRefined] using |
| 134 | + zipWith_thresholdRow_one_sum (wordDescentRefined m r) i.1 |
| 135 | + |
| 136 | +private theorem wordDescentRefined_zero_interlacing (m : ℕ) : |
| 137 | + IsInterlacingSeq0Nonneg (wordDescentRefined m 0) := by |
| 138 | + constructor |
| 139 | + · rw [isInterlacingSeq0_iff_pairwise] |
| 140 | + have hprec : Prec0 (1 : ℝ[X]) 1 := |
| 141 | + (prec_refl (by simp) Polynomial.Splits.one).toPrec0 |
| 142 | + simp [wordDescentRefined, hprec] |
| 143 | + · intro f hf |
| 144 | + simp only [wordDescentRefined, List.mem_replicate] at hf |
| 145 | + rcases hf with ⟨_, rfl⟩ |
| 146 | + exact hasNonnegCoeffs_one |
| 147 | + |
| 148 | +private theorem wordDescentRefined_zero_realRooted (m : ℕ) : |
| 149 | + ∀ f ∈ wordDescentRefined m 0, f ≠ 0 → (f ≠ 0 ∧ f.Splits) := by |
| 150 | + intro f hf _ |
| 151 | + simp only [wordDescentRefined, List.mem_replicate] at hf |
| 152 | + rcases hf with ⟨_, rfl⟩ |
| 153 | + exact ⟨one_ne_zero, Polynomial.Splits.one⟩ |
| 154 | + |
| 155 | +/-- Every last-letter vector is weakly interlacing, and every nonzero |
| 156 | +component is split with nonnegative coefficients. -/ |
| 157 | +theorem wordDescentRefined_interlacing (m r : ℕ) : |
| 158 | + IsInterlacingSeq0Nonneg (wordDescentRefined m r) ∧ |
| 159 | + ∀ f ∈ wordDescentRefined m r, f ≠ 0 → (f ≠ 0 ∧ f.Splits) := by |
| 160 | + induction r with |
| 161 | + | zero => |
| 162 | + exact ⟨wordDescentRefined_zero_interlacing m, wordDescentRefined_zero_realRooted m⟩ |
| 163 | + | succ r ih => |
| 164 | + simpa [wordDescentRefined] using |
| 165 | + haglund_zhang_s_inversion_interlacing_weak |
| 166 | + (wordDescentRows m) (wordDescentRows_data m) (wordDescentRefined m r) |
| 167 | + (length_wordDescentRefined m r) ih.1 ih.2 |
| 168 | + |
| 169 | +/-- The refined sum is nonzero on every nonempty alphabet. -/ |
| 170 | +theorem wordDescentRefined_sum_ne_zero (m : ℕ) (hm : 0 < m) (r : ℕ) : |
| 171 | + (wordDescentRefined m r).sum ≠ 0 := by |
| 172 | + induction r with |
| 173 | + | zero => |
| 174 | + simp [wordDescentRefined, hm.ne'] |
| 175 | + | succ r ih => |
| 176 | + have hdata := wordDescentRefined_interlacing m (r + 1) |
| 177 | + let i : Fin (wordDescentRefined m (r + 1)).length := |
| 178 | + ⟨0, by simpa using hm⟩ |
| 179 | + refine sum_ne_zero_of_hasNonnegCoeffs_of_mem_ne_zero |
| 180 | + hdata.1.2 (List.get_mem _ i) ?_ |
| 181 | + change (wordDescentRefined m (r + 1))[0]'(by simpa using hm) ≠ 0 |
| 182 | + rw [wordDescentRefined_succ_get m r ⟨0, hm⟩] |
| 183 | + simpa using ih |
| 184 | + |
| 185 | +/-- Descent polynomial of all words of length `n` on an alphabet of size `m`. |
| 186 | +The empty word has weight `1`; positive lengths use the last-letter refinement. -/ |
| 187 | +def wordDescentPolynomial (m : ℕ) : ℕ → ℝ[X] |
| 188 | + | 0 => 1 |
| 189 | + | r + 1 => (wordDescentRefined m r).sum |
| 190 | + |
| 191 | +theorem wordDescentPolynomial_ne_zero (m : ℕ) (hm : 0 < m) (n : ℕ) : |
| 192 | + wordDescentPolynomial m n ≠ 0 := by |
| 193 | + cases n with |
| 194 | + | zero => simp [wordDescentPolynomial] |
| 195 | + | succ r => |
| 196 | + simpa [wordDescentPolynomial] using wordDescentRefined_sum_ne_zero m hm r |
| 197 | + |
| 198 | +/-- The recursively defined descent polynomial of all words on a nonempty |
| 199 | +alphabet splits over the reals. -/ |
| 200 | +theorem wordDescentPolynomial_splits (m : ℕ) (hm : 0 < m) (n : ℕ) : |
| 201 | + (wordDescentPolynomial m n).Splits := by |
| 202 | + cases n with |
| 203 | + | zero => simp [wordDescentPolynomial] |
| 204 | + | succ r => |
| 205 | + exact |
| 206 | + (isRealRooted_sum_of_isInterlacingSeq0Nonneg |
| 207 | + (wordDescentRefined_interlacing m r).1 |
| 208 | + (wordDescentRefined_interlacing m r).2 |
| 209 | + (wordDescentRefined_sum_ne_zero m hm r)).2 |
| 210 | + |
| 211 | +end |
| 212 | + |
| 213 | +end RealRooted.ParkingFunctions |
0 commit comments