|
| 1 | +/- |
| 2 | +Copyright (c) 2017 Johannes Hölzl. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: Johannes Hölzl, Johan Commelin, Mario Carneiro |
| 5 | +
|
| 6 | +! This file was ported from Lean 3 source module data.mv_polynomial.rename |
| 7 | +! leanprover-community/mathlib commit eabc6192c84ccce3936a8577a987b80b95ba75f6 |
| 8 | +! Please do not edit these lines, except to modify the commit id |
| 9 | +! if you have ported upstream changes. |
| 10 | +-/ |
| 11 | +import Mathlib.Data.MvPolynomial.Basic |
| 12 | + |
| 13 | +/-! |
| 14 | +# Renaming variables of polynomials |
| 15 | +
|
| 16 | +This file establishes the `rename` operation on multivariate polynomials, |
| 17 | +which modifies the set of variables. |
| 18 | +
|
| 19 | +## Main declarations |
| 20 | +
|
| 21 | +* `MvPolynomial.rename` |
| 22 | +* `MvPolynomial.renameEquiv` |
| 23 | +
|
| 24 | +## Notation |
| 25 | +
|
| 26 | +As in other polynomial files, we typically use the notation: |
| 27 | +
|
| 28 | ++ `σ τ α : Type*` (indexing the variables) |
| 29 | +
|
| 30 | ++ `R S : Type*` `[CommSemiring R]` `[CommSemiring S]` (the coefficients) |
| 31 | +
|
| 32 | ++ `s : σ →₀ ℕ`, a function from `σ` to `ℕ` which is zero away from a finite set. |
| 33 | +This will give rise to a monomial in `MvPolynomial σ R` which mathematicians might call `X^s` |
| 34 | +
|
| 35 | ++ `r : R` elements of the coefficient ring |
| 36 | +
|
| 37 | ++ `i : σ`, with corresponding monomial `X i`, often denoted `X_i` by mathematicians |
| 38 | +
|
| 39 | ++ `p : MvPolynomial σ α` |
| 40 | +
|
| 41 | +-/ |
| 42 | + |
| 43 | + |
| 44 | +noncomputable section |
| 45 | + |
| 46 | +open Classical BigOperators |
| 47 | + |
| 48 | +open Set Function Finsupp AddMonoidAlgebra |
| 49 | + |
| 50 | +open BigOperators |
| 51 | + |
| 52 | +variable {σ τ α R S : Type _} [CommSemiring R] [CommSemiring S] |
| 53 | + |
| 54 | +namespace MvPolynomial |
| 55 | + |
| 56 | +section Rename |
| 57 | + |
| 58 | +/-- Rename all the variables in a multivariable polynomial. -/ |
| 59 | +def rename (f : σ → τ) : MvPolynomial σ R →ₐ[R] MvPolynomial τ R := |
| 60 | + aeval (X ∘ f) |
| 61 | +#align mv_polynomial.rename MvPolynomial.rename |
| 62 | + |
| 63 | +@[simp] |
| 64 | +theorem rename_C (f : σ → τ) (r : R) : rename f (C r) = C r := |
| 65 | + eval₂_C _ _ _ |
| 66 | +set_option linter.uppercaseLean3 false in |
| 67 | +#align mv_polynomial.rename_C MvPolynomial.rename_C |
| 68 | + |
| 69 | +@[simp] |
| 70 | +theorem rename_X (f : σ → τ) (i : σ) : rename f (X i : MvPolynomial σ R) = X (f i) := |
| 71 | + eval₂_X _ _ _ |
| 72 | +set_option linter.uppercaseLean3 false in |
| 73 | +#align mv_polynomial.rename_X MvPolynomial.rename_X |
| 74 | + |
| 75 | +theorem map_rename (f : R →+* S) (g : σ → τ) (p : MvPolynomial σ R) : |
| 76 | + map f (rename g p) = rename g (map f p) := by |
| 77 | + apply MvPolynomial.induction_on p |
| 78 | + (fun a => by simp only [map_C, rename_C]) |
| 79 | + (fun p q hp hq => by simp only [hp, hq, AlgHom.map_add, RingHom.map_add]) fun p n hp => by |
| 80 | + simp only [hp, rename_X, map_X, RingHom.map_mul, AlgHom.map_mul] |
| 81 | +#align mv_polynomial.map_rename MvPolynomial.map_rename |
| 82 | + |
| 83 | +@[simp] |
| 84 | +theorem rename_rename (f : σ → τ) (g : τ → α) (p : MvPolynomial σ R) : |
| 85 | + rename g (rename f p) = rename (g ∘ f) p := |
| 86 | + show rename g (eval₂ C (X ∘ f) p) = _ |
| 87 | + by |
| 88 | + simp only [rename, aeval_eq_eval₂Hom] |
| 89 | + -- porting note: the Lean 3 proof of this was very fragile and included a nonterminal `simp`. |
| 90 | + -- Hopefully this is less prone to breaking |
| 91 | + rw [eval₂_comp_left (eval₂Hom (algebraMap R (MvPolynomial α R)) (X ∘ g)) C (X ∘ f) p] |
| 92 | + simp only [(· ∘ ·), eval₂Hom_X', coe_eval₂Hom] |
| 93 | + refine' eval₂Hom_congr _ rfl rfl |
| 94 | + ext1; simp only [comp_apply, RingHom.coe_comp, eval₂Hom_C] |
| 95 | +#align mv_polynomial.rename_rename MvPolynomial.rename_rename |
| 96 | + |
| 97 | +@[simp] |
| 98 | +theorem rename_id (p : MvPolynomial σ R) : rename id p = p := |
| 99 | + eval₂_eta p |
| 100 | +#align mv_polynomial.rename_id MvPolynomial.rename_id |
| 101 | + |
| 102 | +theorem rename_monomial (f : σ → τ) (d : σ →₀ ℕ) (r : R) : |
| 103 | + rename f (monomial d r) = monomial (d.mapDomain f) r := by |
| 104 | + rw [rename, aeval_monomial, monomial_eq (s := Finsupp.mapDomain f d), |
| 105 | + Finsupp.prod_mapDomain_index] |
| 106 | + · rfl |
| 107 | + · exact fun n => pow_zero _ |
| 108 | + · exact fun n i₁ i₂ => pow_add _ _ _ |
| 109 | +#align mv_polynomial.rename_monomial MvPolynomial.rename_monomial |
| 110 | + |
| 111 | +theorem rename_eq (f : σ → τ) (p : MvPolynomial σ R) : |
| 112 | + rename f p = Finsupp.mapDomain (Finsupp.mapDomain f) p := by |
| 113 | + simp only [rename, aeval_def, eval₂, Finsupp.mapDomain, algebraMap_eq, comp_apply, |
| 114 | + X_pow_eq_monomial, ← monomial_finsupp_sum_index] |
| 115 | + rfl |
| 116 | +#align mv_polynomial.rename_eq MvPolynomial.rename_eq |
| 117 | + |
| 118 | +theorem rename_injective (f : σ → τ) (hf : Function.Injective f) : |
| 119 | + Function.Injective (rename f : MvPolynomial σ R → MvPolynomial τ R) := by |
| 120 | + have : |
| 121 | + (rename f : MvPolynomial σ R → MvPolynomial τ R) = Finsupp.mapDomain (Finsupp.mapDomain f) := |
| 122 | + funext (rename_eq f) |
| 123 | + rw [this] |
| 124 | + exact Finsupp.mapDomain_injective (Finsupp.mapDomain_injective hf) |
| 125 | +#align mv_polynomial.rename_injective MvPolynomial.rename_injective |
| 126 | + |
| 127 | +section |
| 128 | + |
| 129 | +variable {f : σ → τ} (hf : Function.Injective f) |
| 130 | + |
| 131 | +open Classical |
| 132 | + |
| 133 | +/-- Given a function between sets of variables `f : σ → τ` that is injective with proof `hf`, |
| 134 | + `MvPolynomial.killCompl hf` is the `AlgHom` from `R[τ]` to `R[σ]` that is left inverse to |
| 135 | + `rename f : R[σ] → R[τ]` and sends the variables in the complement of the range of `f` to `0`. -/ |
| 136 | +def killCompl : MvPolynomial τ R →ₐ[R] MvPolynomial σ R := |
| 137 | + aeval fun i => if h : i ∈ Set.range f then X <| (Equiv.ofInjective f hf).symm ⟨i, h⟩ else 0 |
| 138 | +#align mv_polynomial.kill_compl MvPolynomial.killCompl |
| 139 | + |
| 140 | +theorem killCompl_comp_rename : (killCompl hf).comp (rename f) = AlgHom.id R _ := |
| 141 | + algHom_ext fun i => by |
| 142 | + dsimp |
| 143 | + rw [rename, killCompl, aeval_X, comp_apply, aeval_X, dif_pos, Equiv.ofInjective_symm_apply] |
| 144 | +#align mv_polynomial.kill_compl_comp_rename MvPolynomial.killCompl_comp_rename |
| 145 | + |
| 146 | +@[simp] |
| 147 | +theorem killCompl_rename_app (p : MvPolynomial σ R) : killCompl hf (rename f p) = p := |
| 148 | + AlgHom.congr_fun (killCompl_comp_rename hf) p |
| 149 | +#align mv_polynomial.kill_compl_rename_app MvPolynomial.killCompl_rename_app |
| 150 | + |
| 151 | +end |
| 152 | + |
| 153 | +section |
| 154 | + |
| 155 | +variable (R) |
| 156 | + |
| 157 | +/-- `MvPolynomial.rename e` is an equivalence when `e` is. -/ |
| 158 | +@[simps apply] |
| 159 | +def renameEquiv (f : σ ≃ τ) : MvPolynomial σ R ≃ₐ[R] MvPolynomial τ R := |
| 160 | + { rename f with |
| 161 | + toFun := rename f |
| 162 | + invFun := rename f.symm |
| 163 | + left_inv := fun p => by rw [rename_rename, f.symm_comp_self, rename_id] |
| 164 | + right_inv := fun p => by rw [rename_rename, f.self_comp_symm, rename_id] } |
| 165 | +#align mv_polynomial.rename_equiv MvPolynomial.renameEquiv |
| 166 | + |
| 167 | +@[simp] |
| 168 | +theorem renameEquiv_refl : renameEquiv R (Equiv.refl σ) = AlgEquiv.refl := |
| 169 | + AlgEquiv.ext rename_id |
| 170 | +#align mv_polynomial.rename_equiv_refl MvPolynomial.renameEquiv_refl |
| 171 | + |
| 172 | +@[simp] |
| 173 | +theorem renameEquiv_symm (f : σ ≃ τ) : (renameEquiv R f).symm = renameEquiv R f.symm := |
| 174 | + rfl |
| 175 | +#align mv_polynomial.rename_equiv_symm MvPolynomial.renameEquiv_symm |
| 176 | + |
| 177 | +@[simp] |
| 178 | +theorem renameEquiv_trans (e : σ ≃ τ) (f : τ ≃ α) : |
| 179 | + (renameEquiv R e).trans (renameEquiv R f) = renameEquiv R (e.trans f) := |
| 180 | + AlgEquiv.ext (rename_rename e f) |
| 181 | +#align mv_polynomial.rename_equiv_trans MvPolynomial.renameEquiv_trans |
| 182 | + |
| 183 | +end |
| 184 | + |
| 185 | +section |
| 186 | + |
| 187 | +variable (f : R →+* S) (k : σ → τ) (g : τ → S) (p : MvPolynomial σ R) |
| 188 | + |
| 189 | +theorem eval₂_rename : (rename k p).eval₂ f g = p.eval₂ f (g ∘ k) := by |
| 190 | + apply MvPolynomial.induction_on p <;> |
| 191 | + · intros |
| 192 | + simp [*] |
| 193 | +#align mv_polynomial.eval₂_rename MvPolynomial.eval₂_rename |
| 194 | + |
| 195 | +theorem eval₂Hom_rename : eval₂Hom f g (rename k p) = eval₂Hom f (g ∘ k) p := |
| 196 | + eval₂_rename _ _ _ _ |
| 197 | +#align mv_polynomial.eval₂_hom_rename MvPolynomial.eval₂Hom_rename |
| 198 | + |
| 199 | +theorem aeval_rename [Algebra R S] : aeval g (rename k p) = aeval (g ∘ k) p := |
| 200 | + eval₂Hom_rename _ _ _ _ |
| 201 | +#align mv_polynomial.aeval_rename MvPolynomial.aeval_rename |
| 202 | + |
| 203 | +theorem rename_eval₂ (g : τ → MvPolynomial σ R) : |
| 204 | + rename k (p.eval₂ C (g ∘ k)) = (rename k p).eval₂ C (rename k ∘ g) := by |
| 205 | + apply MvPolynomial.induction_on p <;> |
| 206 | + · intros |
| 207 | + simp [*] |
| 208 | +#align mv_polynomial.rename_eval₂ MvPolynomial.rename_eval₂ |
| 209 | + |
| 210 | +theorem rename_prodmk_eval₂ (j : τ) (g : σ → MvPolynomial σ R) : |
| 211 | + rename (Prod.mk j) (p.eval₂ C g) = p.eval₂ C fun x => rename (Prod.mk j) (g x) := by |
| 212 | + apply MvPolynomial.induction_on p <;> |
| 213 | + · intros |
| 214 | + simp [*] |
| 215 | +#align mv_polynomial.rename_prodmk_eval₂ MvPolynomial.rename_prodmk_eval₂ |
| 216 | + |
| 217 | +theorem eval₂_rename_prod_mk (g : σ × τ → S) (i : σ) (p : MvPolynomial τ R) : |
| 218 | + (rename (Prod.mk i) p).eval₂ f g = eval₂ f (fun j => g (i, j)) p := by |
| 219 | + apply MvPolynomial.induction_on p <;> |
| 220 | + · intros |
| 221 | + simp [*] |
| 222 | +#align mv_polynomial.eval₂_rename_prodmk MvPolynomial.eval₂_rename_prod_mk |
| 223 | + |
| 224 | +theorem eval_rename_prod_mk (g : σ × τ → R) (i : σ) (p : MvPolynomial τ R) : |
| 225 | + eval g (rename (Prod.mk i) p) = eval (fun j => g (i, j)) p := |
| 226 | + eval₂_rename_prod_mk (RingHom.id _) _ _ _ |
| 227 | +#align mv_polynomial.eval_rename_prodmk MvPolynomial.eval_rename_prod_mk |
| 228 | + |
| 229 | +end |
| 230 | + |
| 231 | +/-- Every polynomial is a polynomial in finitely many variables. -/ |
| 232 | +theorem exists_finset_rename (p : MvPolynomial σ R) : |
| 233 | + ∃ (s : Finset σ)(q : MvPolynomial { x // x ∈ s } R), p = rename (↑) q := by |
| 234 | + apply induction_on p |
| 235 | + · intro r |
| 236 | + exact ⟨∅, C r, by rw [rename_C]⟩ |
| 237 | + · rintro p q ⟨s, p, rfl⟩ ⟨t, q, rfl⟩ |
| 238 | + refine' ⟨s ∪ t, ⟨_, _⟩⟩ |
| 239 | + · |
| 240 | + refine' rename (Subtype.map id _) p + rename (Subtype.map id _) q <;> |
| 241 | + simp (config := { contextual := true }) only [id.def, true_or_iff, or_true_iff, |
| 242 | + Finset.mem_union, forall_true_iff] |
| 243 | + · simp only [rename_rename, AlgHom.map_add] |
| 244 | + rfl |
| 245 | + · rintro p n ⟨s, p, rfl⟩ |
| 246 | + refine' ⟨insert n s, ⟨_, _⟩⟩ |
| 247 | + · refine' rename (Subtype.map id _) p * X ⟨n, s.mem_insert_self n⟩ |
| 248 | + simp (config := { contextual := true }) only [id.def, or_true_iff, Finset.mem_insert, |
| 249 | + forall_true_iff] |
| 250 | + · simp only [rename_rename, rename_X, Subtype.coe_mk, AlgHom.map_mul] |
| 251 | + rfl |
| 252 | +#align mv_polynomial.exists_finset_rename MvPolynomial.exists_finset_rename |
| 253 | + |
| 254 | +/-- `exists_finset_rename` for two polyonomials at once: for any two polynomials `p₁`, `p₂` in a |
| 255 | + polynomial semiring `R[σ]` of possibly infinitely many variables, `exists_finset_rename₂` yields |
| 256 | + a finite subset `s` of `σ` such that both `p₁` and `p₂` are contained in the polynomial semiring |
| 257 | + `R[s]` of finitely many variables. -/ |
| 258 | +theorem exists_finset_rename₂ (p₁ p₂ : MvPolynomial σ R) : |
| 259 | + ∃ (s : Finset σ)(q₁ q₂ : MvPolynomial s R), p₁ = rename (↑) q₁ ∧ p₂ = rename (↑) q₂ := by |
| 260 | + obtain ⟨s₁, q₁, rfl⟩ := exists_finset_rename p₁ |
| 261 | + obtain ⟨s₂, q₂, rfl⟩ := exists_finset_rename p₂ |
| 262 | + classical |
| 263 | + use s₁ ∪ s₂ |
| 264 | + use rename (Set.inclusion <| s₁.subset_union_left s₂) q₁ |
| 265 | + use rename (Set.inclusion <| s₁.subset_union_right s₂) q₂ |
| 266 | + constructor -- porting note: was `<;> simp <;> rfl` but Lean couldn't infer the arguments |
| 267 | + · rw [rename_rename (Set.inclusion <| s₁.subset_union_left s₂)] |
| 268 | + rfl |
| 269 | + · rw [rename_rename (Set.inclusion <| s₁.subset_union_right s₂)] |
| 270 | + rfl |
| 271 | +#align mv_polynomial.exists_finset_rename₂ MvPolynomial.exists_finset_rename₂ |
| 272 | + |
| 273 | +/-- Every polynomial is a polynomial in finitely many variables. -/ |
| 274 | +theorem exists_fin_rename (p : MvPolynomial σ R) : |
| 275 | + ∃ (n : ℕ)(f : Fin n → σ) (_hf : Injective f)(q : MvPolynomial (Fin n) R), p = rename f q := by |
| 276 | + obtain ⟨s, q, rfl⟩ := exists_finset_rename p |
| 277 | + let n := Fintype.card { x // x ∈ s } |
| 278 | + let e := Fintype.equivFin { x // x ∈ s } |
| 279 | + refine' ⟨n, (↑) ∘ e.symm, Subtype.val_injective.comp e.symm.injective, rename e q, _⟩ |
| 280 | + rw [← rename_rename, rename_rename e] |
| 281 | + simp only [Function.comp, Equiv.symm_apply_apply, rename_rename] |
| 282 | +#align mv_polynomial.exists_fin_rename MvPolynomial.exists_fin_rename |
| 283 | + |
| 284 | +end Rename |
| 285 | + |
| 286 | +theorem eval₂_cast_comp (f : σ → τ) (c : ℤ →+* R) (g : τ → R) (p : MvPolynomial σ ℤ) : |
| 287 | + eval₂ c (g ∘ f) p = eval₂ c g (rename f p) := by |
| 288 | + apply MvPolynomial.induction_on p (fun n => by simp only [eval₂_C, rename_C]) |
| 289 | + (fun p q hp hq => by simp only [hp, hq, rename, eval₂_add, AlgHom.map_add]) |
| 290 | + fun p n hp => by simp only [eval₂_mul, hp, eval₂_X, comp_apply, map_mul, rename_X, eval₂_mul] |
| 291 | +#align mv_polynomial.eval₂_cast_comp MvPolynomial.eval₂_cast_comp |
| 292 | + |
| 293 | +section Coeff |
| 294 | + |
| 295 | +@[simp] |
| 296 | +theorem coeff_rename_mapDomain (f : σ → τ) (hf : Injective f) (φ : MvPolynomial σ R) (d : σ →₀ ℕ) : |
| 297 | + (rename f φ).coeff (d.mapDomain f) = φ.coeff d := by |
| 298 | + apply φ.induction_on' (P := fun ψ => coeff (Finsupp.mapDomain f d) ((rename f) ψ) = coeff d ψ) |
| 299 | + -- Lean could no longer infer the motive |
| 300 | + · intro u r |
| 301 | + rw [rename_monomial, coeff_monomial, coeff_monomial] |
| 302 | + simp only [(Finsupp.mapDomain_injective hf).eq_iff] |
| 303 | + · intros |
| 304 | + simp only [*, AlgHom.map_add, coeff_add] |
| 305 | +#align mv_polynomial.coeff_rename_map_domain MvPolynomial.coeff_rename_mapDomain |
| 306 | + |
| 307 | +theorem coeff_rename_eq_zero (f : σ → τ) (φ : MvPolynomial σ R) (d : τ →₀ ℕ) |
| 308 | + (h : ∀ u : σ →₀ ℕ, u.mapDomain f = d → φ.coeff u = 0) : (rename f φ).coeff d = 0 := by |
| 309 | + rw [rename_eq, ← not_mem_support_iff] |
| 310 | + intro H |
| 311 | + replace H := mapDomain_support H |
| 312 | + rw [Finset.mem_image] at H |
| 313 | + obtain ⟨u, hu, rfl⟩ := H |
| 314 | + specialize h u rfl |
| 315 | + simp at h hu |
| 316 | + contradiction |
| 317 | +#align mv_polynomial.coeff_rename_eq_zero MvPolynomial.coeff_rename_eq_zero |
| 318 | + |
| 319 | +theorem coeff_rename_ne_zero (f : σ → τ) (φ : MvPolynomial σ R) (d : τ →₀ ℕ) |
| 320 | + (h : (rename f φ).coeff d ≠ 0) : ∃ u : σ →₀ ℕ, u.mapDomain f = d ∧ φ.coeff u ≠ 0 := by |
| 321 | + contrapose! h |
| 322 | + apply coeff_rename_eq_zero _ _ _ h |
| 323 | +#align mv_polynomial.coeff_rename_ne_zero MvPolynomial.coeff_rename_ne_zero |
| 324 | + |
| 325 | +@[simp] |
| 326 | +theorem constantCoeff_rename {τ : Type _} (f : σ → τ) (φ : MvPolynomial σ R) : |
| 327 | + constantCoeff (rename f φ) = constantCoeff φ := by |
| 328 | + apply φ.induction_on |
| 329 | + · intro a |
| 330 | + simp only [constantCoeff_C, rename_C] |
| 331 | + · intro p q hp hq |
| 332 | + simp only [hp, hq, RingHom.map_add, AlgHom.map_add] |
| 333 | + · intro p n hp |
| 334 | + simp only [hp, rename_X, constantCoeff_X, RingHom.map_mul, AlgHom.map_mul] |
| 335 | +#align mv_polynomial.constant_coeff_rename MvPolynomial.constantCoeff_rename |
| 336 | + |
| 337 | +end Coeff |
| 338 | + |
| 339 | +section Support |
| 340 | + |
| 341 | +theorem support_rename_of_injective {p : MvPolynomial σ R} {f : σ → τ} (h : Function.Injective f) : |
| 342 | + (rename f p).support = Finset.image (Finsupp.mapDomain f) p.support := by |
| 343 | + rw [rename_eq] |
| 344 | + exact Finsupp.mapDomain_support_of_injective (mapDomain_injective h) _ |
| 345 | +#align mv_polynomial.support_rename_of_injective MvPolynomial.support_rename_of_injective |
| 346 | + |
| 347 | +end Support |
| 348 | + |
| 349 | +end MvPolynomial |
0 commit comments