1-- Explicit monic polynomials vanishing on finite lists, without Choice.2-- Part of Cumulus, the Grace17 mathematics library.3-- Copyright (c) 2026 Grant Passmore.4-- Released under the Apache License 2.0. See LICENSE in the repository root.5-- Authors: Grant Passmore67module Grace.Cumulus.Algebra.Polynomial.MonicVanishing8import Horner9import Cardinal.ListSupport1011-- If cs represents the monic polynomial P, this list represents carry+(X-a)P.12def hornerLinearProduct {A : Set} (add neg mul a carry : Set) (cs : List(A)) →Set13| add, neg, mul, a, carry, List.nil => [call2(add, carry, neg(a))]14| add, neg, mul, a, carry, List.cons(c, tail) => call2(add, carry, neg(call2(mul, a, c))) :: hornerLinearProduct(add, neg, mul, a, c, tail)15descends cs1617section Rings18variable (A add zero neg mul one a : Set)19notationring R := (A, add, zero, neg, mul, one)20hypothesisring : IsCommRing(R)21hypothesis center : a ∈ R2223theorem hornerLinearProduct.closed (carry : Set) (cs : List(A))24requires constant : carry ∈ R25shows List(A, hornerLinearProduct{A}(add, neg, mul, a, carry, cs))26proof27induction cs generalizing carry28| List.nil =>29intros carry constant30have ordinary := IsCommRing.ring withring31have negative := IsRing.neg_closed with ordinary, center32have head := IsRing.add_closed with ordinary, constant, negative33rw hornerLinearProduct34typecheck35| List.cons(c, tail) using ih =>36intros carry constant37have ordinary := IsCommRing.ring withring38have coefficient : c ∈ R byassumption39have rest := ih with c, coefficient40have product := IsRing.mul_closed with ordinary, center, coefficient41have negative := IsRing.neg_closed with ordinary, product42have head := IsRing.add_closed with ordinary, constant, negative43rw hornerLinearProduct44typecheck4546theorem hornerLinearProduct.value (x carry : Set) (cs : List(A))47requires element : x ∈ R48requires constant : carry ∈ R49shows hornerAt{A}(add, mul, one, x, hornerLinearProduct{A}(add, neg, mul, a, carry, cs)) = R[carry + (x - a) * hornerAt{A}(add, mul, one, x, cs)]50proof51induction cs generalizing carry52| List.nil =>53intros carry constant54have ordinary := IsCommRing.ring withring55have negative := IsRing.neg_closed with ordinary, center56have coefficient := IsRing.add_closed with ordinary, constant, negative57have empty : List(A, []) bytypecheck58rw [hornerLinearProduct, hornerAt.cons, hornerAt.nil]59ring60| List.cons(c, tail) using ih =>61intros carry constant62have ordinary := IsCommRing.ring withring63have coefficient : c ∈ R byassumption64have product := IsRing.mul_closed with ordinary, center, coefficient65have negative := IsRing.neg_closed with ordinary, product66have productCoefficient := IsRing.add_closed with ordinary, constant,67 negative68have multiplicative := IsRing.multiplicative with ordinary69have unitIn := IsMonoid.unit_in_carrier with multiplicative70have rest := hornerLinearProduct.closed at A, add, zero, neg, mul, one, a, c, tail with*71have tailValue := hornerAt.closed at A, add, zero, neg, mul, one, one, x, tail with*72have previous := ih with c, coefficient73have outer := hornerAt.cons at A, add, mul, one, x, R[carry - a * c], hornerLinearProduct{A}(add, neg, mul, a, c, tail) with*74have original := hornerAt.cons at A, add, mul, one, x, c, tail with*75rw [hornerLinearProduct, outer, original, previous]76ring7778end Rings7980section FiniteSets81variable (A add zero neg mul one : Set)82notationring R := (A, add, zero, neg, mul, one)83hypothesisring : IsCommRing(R)8485-- Starting with X guarantees positive degree, even for an empty covering list.86theorem hornerAt.monic_vanishing_on_list (xs : List(A))87shows∃ c ∈ R, ∃ cs, List(A, cs) ∧ (∀ x ∈ R, x ∈ listSupport{A}(xs) → hornerAt{A}(add, mul, one, x, c :: cs) = R[0])88proof89induction xs90| List.nil =>91have ordinary := IsCommRing.ring withring92have zeroIn := IsRing.zero_in_carrier with ordinary93have empty : List(A, []) bytypecheck94refine⟨zero, zeroIn, [], empty, ?_⟩95intros x element impossible96rw listSupport at impossible97exfalso98exactset.empty with impossible99| List.cons(a, tail) using ih =>100have ordinary := IsCommRing.ring withring101have center : a ∈ R byassumption102obtain⟨c, coefficient, cs, list, vanishes⟩:= ih103have zeroIn := IsRing.zero_in_carrier with ordinary104have productCoefficient := IsRing.mul_closed with ordinary, center, coefficient105have newCoefficient := IsRing.neg_closed with ordinary, productCoefficient106have newList := hornerLinearProduct.closed at A, add, zero, neg, mul, one, a, c, cs with*107refine⟨R[-(a * c)], newCoefficient, hornerLinearProduct{A}(add, neg, mul, a, c, cs), newList, ?_⟩108intros x element member109have multiplicative := IsRing.multiplicative with ordinary110have unitIn := IsMonoid.unit_in_carrier with multiplicative111have value := hornerAt.closed at A, add, zero, neg, mul, one, one, x, c :: cs with*112have product := hornerLinearProduct.value at A, add, zero, neg, mul, one, a, x, zero, c :: cs with*113rw hornerLinearProduct at product114have head : R[0 - a * c] = R[-(a * c)] byring115rw head at product116rw product117rw listSupport at member118have alternatives := insert.membership.forward with member119cases alternatives with same | previous120 . rw same at value121rw same122ring123 . have old := vanishes with x, element, previous124rw old125ring126127end FiniteSets128