Documentation

HexPoly.Operations

noncomputable def Hex.DensePoly.scale {R : Type u} [Zero R] [DecidableEq R] [Mul R] (c : R) (p : DensePoly R) :

Multiply every coefficient by c.

Kernel-facing specification: one map over the reference coefficient list. Compiled code uses Hex.DensePoly.scaleImpl, the value-equal Array.map pass selected by Hex.DensePoly.scale_eq_impl.

Equations
Instances For
    def Hex.DensePoly.scaleImpl {R : Type u} [Zero R] [DecidableEq R] [Mul R] (c : R) (p : DensePoly R) :

    Runtime implementation of scale: one Array.map pass over the stored coefficients (value-equal to scale by scale_eq_impl, registered @[csimp]).

    Equations
    Instances For
      theorem Hex.DensePoly.scale_eq_scaleImpl {R : Type u} [Zero R] [DecidableEq R] [Mul R] (c : R) (p : DensePoly R) :
      scale c p = scaleImpl c p

      The reference scale and the Array.map runtime pass compute the same polynomial.

      theorem Hex.DensePoly.size_scaleImpl_le {R : Type u} [Zero R] [DecidableEq R] [Mul R] (c : R) (p : DensePoly R) :

      Coefficientwise scaling cannot increase the stored polynomial size.

      @[csimp]

      Register the Array.map pass as the compiled implementation of scale.

      noncomputable def Hex.DensePoly.shift {R : Type u} [Zero R] [DecidableEq R] (n : Nat) (p : DensePoly R) :

      Multiply by x^n.

      Kernel-facing specification: one replicate-append of the reference coefficient list. Compiled code uses Hex.DensePoly.shiftImpl, the value-equal Array.append implementation selected by Hex.DensePoly.shift_eq_impl.

      Equations
      Instances For
        def Hex.DensePoly.shiftImpl {R : Type u} [Zero R] [DecidableEq R] (n : Nat) (p : DensePoly R) :

        Runtime implementation of shift: one Array append with no intermediate list (value-equal to shift by shift_eq_impl, registered @[csimp]).

        Equations
        Instances For
          theorem Hex.DensePoly.shift_eq_shiftImpl {R : Type u} [Zero R] [DecidableEq R] (n : Nat) (p : DensePoly R) :
          shift n p = shiftImpl n p

          The reference shift and the Array append compute the same polynomial.

          @[csimp]

          Register the Array append as the compiled implementation of shift.

          theorem Hex.DensePoly.coeff_scale {R : Type u} [Zero R] [DecidableEq R] [Mul R] (c : R) (p : DensePoly R) (n : Nat) (hzero : c * Zero.zero = Zero.zero) :
          (scale c p).coeff n = c * p.coeff n

          Coefficient law for scalar multiplication. The explicit zero law records the fact that scaling a missing coefficient still gives the default coefficient 0.

          @[simp]
          theorem Hex.DensePoly.scale_zero_right {R : Type u} [Zero R] [DecidableEq R] [Mul R] (c : R) :
          scale c 0 = 0

          Scaling the zero polynomial yields the zero polynomial: scale c 0 = 0. A simp/grind normal form, so callers need no c * 0 = 0 hypothesis to discharge the scaled-zero case.

          @[simp]
          theorem Hex.DensePoly.coeff_scale_semiring {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] (c : S) (p : DensePoly S) (n : Nat) :
          (scale c p).coeff n = c * p.coeff n

          Semiring-specialized coefficient law for scalar multiplication, registered as a normalizing rewrite because the required c * 0 = 0 law is available from the semiring structure.

          theorem Hex.DensePoly.scale_scale {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] (a b : S) (p : DensePoly S) :
          scale a (scale b p) = scale (a * b) p

          Scaling twice multiplies the two scalars.

          @[simp]

          Semiring-specialized left zero law for scalar multiplication.

          @[simp]
          theorem Hex.DensePoly.coeff_shift {R : Type u} [Zero R] [DecidableEq R] (n : Nat) (p : DensePoly R) (k : Nat) :
          (shift n p).coeff k = if k < n then Zero.zero else p.coeff (k - n)

          Coefficient law for shifting by x^n: coefficients below n are zero and later coefficients are read from the original polynomial with the index shifted down.

          @[simp]
          theorem Hex.DensePoly.shift_zero_right {R : Type u} [Zero R] [DecidableEq R] (n : Nat) :
          shift n 0 = 0

          Shifting the zero polynomial by any power leaves it zero: shift n 0 = 0. A simp/grind normal form for the degenerate input to shift.

          @[simp]
          theorem Hex.DensePoly.shift_zero_left {R : Type u} [Zero R] [DecidableEq R] (p : DensePoly R) :
          shift 0 p = p

          Shifting by x^0 is the identity: shift 0 p = p. A simp/grind normal form so a trivial shift drops out of multiplication and division proofs.

          theorem Hex.DensePoly.coeff_shift_scale {R : Type u} [Zero R] [DecidableEq R] [Mul R] (i : Nat) (c : R) (p : DensePoly R) (k : Nat) (hzero : c * Zero.zero = Zero.zero) :
          (shift i (scale c p)).coeff k = if k < i then Zero.zero else c * p.coeff (k - i)

          Combined coefficient law for a scaled shift. The zero-law hypothesis is the only algebraic fact needed to normalize coefficients that are outside the support.

          @[simp]
          theorem Hex.DensePoly.coeff_shift_scale_semiring {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] (i : Nat) (c : S) (p : DensePoly S) (k : Nat) :
          (shift i (scale c p)).coeff k = if k < i then Zero.zero else c * p.coeff (k - i)

          Semiring-specialized coefficient law for a scaled shift, registered as a normalizing rewrite for the common algebraic setting.

          Reading the reference coefficient list with default zero agrees with DensePoly.coeff.

          @[simp]
          theorem Hex.DensePoly.coeff_zero {R : Type u} [Zero R] [DecidableEq R] (n : Nat) :
          coeff 0 n = 0

          The zero polynomial has coefficient 0 at every index.

          def Hex.DensePoly.zipPad {R : Type u} [Zero R] (f : RRR) :
          List RList RList R

          Zip two coefficient lists with f, padding the shorter list with literal Zero.zero arguments: overhang entries become f p Zero.zero / f Zero.zero q rather than being passed through, so every output entry is literally f (xs.getD i) (ys.getD i); the value the Array.ofFn runtime impls reproduce with no algebraic laws on R.

          Equations
          Instances For
            noncomputable def Hex.DensePoly.add {R : Type u} [Zero R] [DecidableEq R] [Add R] (p q : DensePoly R) :

            Add two dense polynomials coefficientwise.

            Kernel-facing specification: a single padded walk of the two coefficient lists. Compiled code uses Hex.DensePoly.addImpl, the value-equal, one-allocation Array.ofFn loop selected by Hex.DensePoly.add_eq_impl.

            Equations
            Instances For
              def Hex.DensePoly.addImpl {R : Type u} [Zero R] [DecidableEq R] [Add R] (p q : DensePoly R) :

              Runtime implementation of add: one Array.ofFn allocation over the padded index range (value-equal to add by add_eq_impl, registered @[csimp]).

              Equations
              Instances For
                theorem Hex.DensePoly.add_eq_addImpl {R : Type u} [Zero R] [DecidableEq R] [Add R] (p q : DensePoly R) :
                p.add q = p.addImpl q

                The reference add and the Array.ofFn runtime loop compute the same polynomial: each output coefficient is literally p.coeff i + q.coeff i on both sides, so no algebraic laws on R are needed.

                @[csimp]

                Register the Array.ofFn loop as the compiled implementation of add.

                @[instance_reducible]
                instance Hex.DensePoly.instAdd {R : Type u} [Zero R] [DecidableEq R] [Add R] :
                Equations
                noncomputable def Hex.DensePoly.sub {R : Type u} [Zero R] [DecidableEq R] [Sub R] (p q : DensePoly R) :

                Subtract two dense polynomials coefficientwise.

                Like Hex.DensePoly.add, this is a kernel-reduction-friendly specification. Compiled code uses Hex.DensePoly.subImpl, the value-equal Array.ofFn loop selected by Hex.DensePoly.sub_eq_impl.

                Equations
                Instances For
                  def Hex.DensePoly.subImpl {R : Type u} [Zero R] [DecidableEq R] [Sub R] (p q : DensePoly R) :

                  Runtime implementation of sub (value-equal to sub by sub_eq_impl, registered @[csimp]).

                  Equations
                  Instances For
                    theorem Hex.DensePoly.sub_eq_subImpl {R : Type u} [Zero R] [DecidableEq R] [Sub R] (p q : DensePoly R) :
                    p.sub q = p.subImpl q

                    The reference sub and the Array.ofFn runtime loop compute the same polynomial.

                    @[csimp]

                    Register the Array.ofFn loop as the compiled implementation of sub.

                    @[instance_reducible]
                    instance Hex.DensePoly.instSub {R : Type u} [Zero R] [DecidableEq R] [Sub R] :
                    Equations
                    noncomputable def Hex.DensePoly.neg {R : Type u} [Zero R] [DecidableEq R] [Sub R] (p : DensePoly R) :

                    Coefficientwise additive inverse, expressed through executable subtraction.

                    Kernel-facing specification (one Hex.DensePoly.sub against the zero polynomial); compiled code uses Hex.DensePoly.negImpl, the value-equal Array.map pass selected by Hex.DensePoly.neg_eq_impl.

                    Equations
                    Instances For
                      def Hex.DensePoly.negImpl {R : Type u} [Zero R] [DecidableEq R] [Sub R] (p : DensePoly R) :

                      Runtime implementation of neg: one Array.map pass over the stored coefficients (value-equal to neg by neg_eq_impl, registered @[csimp]).

                      Equations
                      Instances For
                        theorem Hex.DensePoly.neg_eq_negImpl {R : Type u} [Zero R] [DecidableEq R] [Sub R] (p : DensePoly R) :

                        The reference neg and the Array.map runtime pass compute the same polynomial: each coefficient is literally Zero.zero - p.coeff i on both sides.

                        @[csimp]

                        Register the Array.map pass as the compiled implementation of neg.

                        @[instance_reducible]
                        instance Hex.DensePoly.instNegOfSub {R : Type u} [Zero R] [DecidableEq R] [Sub R] :
                        Equations
                        class Hex.DensePoly.AddZeroLaw (S : Type u) [Zero S] [Add S] :

                        Compatibility law for caller-facing Zero/Add instances used by semiring wrappers.

                        Instances

                          Semiring structures provide the zero-addition compatibility law used by coefficient lemmas.

                          class Hex.DensePoly.SubZeroLaw (S : Type u) [Zero S] [Sub S] :

                          Compatibility law for caller-facing Zero/Sub instances used by ring wrappers.

                          Instances

                            Ring structures provide the zero-subtraction compatibility law used by coefficient lemmas.

                            class Hex.DensePoly.ZeroSubNegLaw (S : Type u) [Zero S] [Sub S] [Neg S] :

                            Compatibility law for caller-facing Zero/Sub/Neg instances used by negation wrappers.

                            Instances

                              Ring structures provide the zero-subtraction negation law used by coefficient lemmas.

                              def Hex.DensePoly.mulRow {R : Type u} [Add R] [Mul R] (c : R) :
                              List RList RList R

                              One row of the schoolbook convolution: add c times each entry of qs into the corresponding entry of acc, dropping contributions past the end of acc (matching the dropped out-of-bounds Array.set! writes of mulImpl).

                              Equations
                              Instances For
                                def Hex.DensePoly.mulRows {R : Type u} [Add R] [Mul R] (qs : List R) :
                                List RList RList R

                                All rows of the schoolbook convolution: for each coefficient of ps in ascending-degree order, add its scaled copy of qs into the accumulator at the matching offset. The accumulator entry at the current offset is final once its row is applied, so each step emits one finished coefficient and recurses on the tail. Additions reach each accumulator entry in exactly the order of the Array-based mulImpl loop, which is what makes mul_eq_impl provable without any algebraic laws on R.

                                Equations
                                Instances For
                                  noncomputable def Hex.DensePoly.mul {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p q : DensePoly R) :

                                  Schoolbook dense polynomial multiplication by direct coefficient convolution.

                                  This definition is the kernel-reduction-friendly specification: the accumulator is a plain list walked head-first, so reducing a concrete product costs one cons-step per (i, j) coefficient pair instead of an O(size) list traversal per Array access. Compiled code instead runs the in-place Array loop Hex.DensePoly.mulImpl, selected by Hex.DensePoly.mul_eq_impl.

                                  Equations
                                  • One or more equations did not get rendered due to their size.
                                  Instances For
                                    def Hex.DensePoly.mulImpl {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p q : DensePoly R) :

                                    Runtime implementation of mul: the same schoolbook convolution computed by in-place Array writes (value-equal to mul by mul_eq_impl, registered @[csimp]).

                                    The inner j-loop reads the loop-invariant coefficient p.coeff i from a single let-bound value (pi) instead of re-projecting it on every (i, j) step, so the compiled inner loop performs one bounds-checked coefficient read per i rather than per (i, j). The let is a zeta reduction away from the bare convolution, so it does not change the value, the coeff_mul characterization, or any proof.

                                    Equations
                                    • One or more equations did not get rendered due to their size.
                                    Instances For
                                      def Hex.DensePoly.mulCoeffStep {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p q : DensePoly R) (n i : Nat) (acc : R) (j : Nat) :
                                      R

                                      One inner schoolbook multiplication step, projected to coefficient n.

                                      Equations
                                      Instances For
                                        def Hex.DensePoly.mulCoeffSum {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p q : DensePoly R) (n : Nat) :
                                        R

                                        The schoolbook coefficient fold matching the executable multiplication loop order.

                                        Equations
                                        Instances For
                                          theorem Hex.DensePoly.mulCoeffSum_eq_singleFold {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p q : DensePoly R) (n : Nat) :
                                          p.mulCoeffSum q n = List.foldl (fun (c : R) (i : Nat) => if i n n - i < q.size then c + p.coeff i * q.coeff (n - i) else c) Zero.zero (List.range p.size)

                                          mulCoeffSum collapsed to a single fold over the row index i, each row contributing p.coeff i * q.coeff (n - i) when i ≤ n and n - i is in range (closed form from foldl_mulCoeffStep_range). Public so lazy-reduction convolution kernels can relate their per-coefficient Nat sums to the reference product coefficient.

                                          theorem Hex.DensePoly.mul_eq_mulImpl {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p q : DensePoly R) :
                                          p.mul q = p.mulImpl q

                                          The specification mul and the Array-loop mulImpl compute the same polynomial: both sides perform the same coefficient additions in the same order, so no algebraic laws on R are needed.

                                          @[csimp]

                                          Register the Array-loop mulImpl as the compiled implementation of mul. As with trimTrailingZeros_eq_impl, the @[csimp] swap is backed by a proof, so the runtime loop is verified equal to the kernel-facing specification.

                                          @[instance_reducible]
                                          instance Hex.DensePoly.instMulOfAdd {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] :
                                          Equations
                                          theorem Hex.DensePoly.coeff_mul {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p q : DensePoly R) (n : Nat) :
                                          (p * q).coeff n = p.mulCoeffSum q n

                                          Characterising coefficient law for multiplication: each coefficient of p * q is computed by the same nested schoolbook fold as the executable multiplication loop.

                                          theorem Hex.DensePoly.size_mul_le {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p q : DensePoly R) :
                                          (p * q).size p.size + q.size - 1

                                          A product stores at most p.size + q.size - 1 coefficients.

                                          def Hex.DensePoly.evalCoeffList {R : Type u} [Zero R] [Add R] [Mul R] :
                                          List RRR

                                          List-level Horner evaluation, reading coefficients from low to high degree. The body of the eval specification.

                                          Equations
                                          Instances For
                                            noncomputable def Hex.DensePoly.eval {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p : DensePoly R) (x : R) :
                                            R

                                            Evaluate a polynomial using Horner's method.

                                            Kernel-facing specification: one cons walk of the coefficient list, highest degree innermost. Compiled code uses Hex.DensePoly.evalImpl, the value-equal downward Array.foldr loop with no intermediate list or reverse allocation, selected by Hex.DensePoly.eval_eq_impl.

                                            Equations
                                            Instances For
                                              def Hex.DensePoly.evalImpl {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p : DensePoly R) (x : R) :
                                              R

                                              Runtime implementation of eval: a downward Array.foldr Horner loop over the stored coefficients, with no intermediate coefficient-list or reverse allocation (value-equal to eval by eval_eq_impl, registered @[csimp]).

                                              Equations
                                              Instances For
                                                theorem Hex.DensePoly.eval_eq_evalImpl {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p : DensePoly R) (x : R) :
                                                p.eval x = p.evalImpl x

                                                The reference eval and the Array.foldr runtime loop compute the same value.

                                                @[csimp]

                                                Register the Array.foldr loop as the compiled implementation of eval.

                                                List-level Horner composition, reading coefficients from low to high degree and preserving the acc * q + C c step orientation (for generic R this differs from composeScalarCoeffList's C c + q * acc).

                                                Equations
                                                Instances For
                                                  noncomputable def Hex.DensePoly.compose {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p q : DensePoly R) :

                                                  Compose polynomials using Horner's method.

                                                  Kernel-facing specification: one cons walk of the coefficient list. Compiled code uses Hex.DensePoly.composeImpl, the value-equal downward Array.foldr loop selected by Hex.DensePoly.compose_eq_impl.

                                                  Equations
                                                  Instances For
                                                    def Hex.DensePoly.composeImpl {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p q : DensePoly R) :

                                                    Runtime implementation of compose: a downward Array.foldr Horner loop (value-equal to compose by compose_eq_impl, registered @[csimp]).

                                                    Equations
                                                    Instances For
                                                      theorem Hex.DensePoly.compose_eq_composeImpl {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p q : DensePoly R) :

                                                      The reference compose and the Array.foldr runtime loop compute the same polynomial.

                                                      @[csimp]

                                                      Register the Array.foldr loop as the compiled implementation of compose.

                                                      @[simp]
                                                      theorem Hex.DensePoly.compose_zero_left {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (q : DensePoly R) :
                                                      compose 0 q = 0

                                                      Left-composition by the zero polynomial is zero.

                                                      theorem Hex.DensePoly.compose_C {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (c : R) (q : DensePoly R) (hzero_add : Zero.zero + c = c) :
                                                      (C c).compose q = C c

                                                      Composition of a constant polynomial. The explicit zero-addition law is needed because the generic Add/Mul/Zero interfaces do not provide algebraic simplification rules.

                                                      @[simp]
                                                      theorem Hex.DensePoly.compose_C_semiring {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] (c : S) (q : DensePoly S) :
                                                      (C c).compose q = C c

                                                      Semiring-specialized composition law for constants. This packages the zero-addition law needed by the generic compose_C.

                                                      List-level Horner form for composition, reading coefficients from low to high degree.

                                                      Equations
                                                      Instances For
                                                        theorem Hex.DensePoly.compose_eq_composeScalarCoeffList_of_step {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p q : DensePoly R) (hstep : ∀ (acc : DensePoly R) (c : R), acc * q + C c = C c + q * acc) :

                                                        DensePoly.compose agrees with the list-level Horner form over the stored coefficients when the caller supplies the algebraic step that commutes a Horner tail past q.

                                                        def Hex.DensePoly.composePower {R : Type u} [Zero R] [DecidableEq R] [One R] [Add R] [Mul R] (q : DensePoly R) :

                                                        Iterated polynomial power used by the compose power-sum characterisation.

                                                        Equations
                                                        Instances For
                                                          def Hex.DensePoly.composeCoeffPowerSumFrom {R : Type u} [Zero R] [DecidableEq R] [One R] [Add R] [Mul R] :
                                                          List RNatDensePoly RDensePoly R

                                                          List-backed power-sum form for composition, starting at a coefficient base index.

                                                          Equations
                                                          Instances For
                                                            def Hex.DensePoly.composeCoeffPowerSumUpTo {R : Type u} [Zero R] [DecidableEq R] [One R] [Add R] [Mul R] (coeff : NatR) :
                                                            NatNatDensePoly RDensePoly R

                                                            Coefficient-indexed bounded power-sum form for composition.

                                                            Equations
                                                            Instances For
                                                              theorem Hex.DensePoly.composeCoeffPowerSumFrom_range_eq_upTo {R : Type u} [Zero R] [DecidableEq R] [One R] [Add R] [Mul R] (coeff : NatR) (q : DensePoly R) (n base : Nat) :
                                                              composeCoeffPowerSumFrom (List.map (fun (i : Nat) => coeff (base + i)) (List.range n)) base q = composeCoeffPowerSumUpTo coeff n base q

                                                              composeCoeffPowerSumFrom over a consecutive range is the bounded coefficient-indexed power sum.

                                                              theorem Hex.DensePoly.toList_eq_coeff_range {R : Type u} [Zero R] [DecidableEq R] (p : DensePoly R) :
                                                              p.toList = List.map (fun (i : Nat) => p.coeff i) (List.range p.size)

                                                              The reference coefficient list is the range of coefficient reads over p.size.

                                                              def Hex.DensePoly.derivList {R : Type u} [NatCast R] [Mul R] :
                                                              NatList RList R

                                                              Index-carrying derivative walk: entry j of derivList i cs is ((i + j + 1 : Nat) : R) * cs[j]. Applied at i = 0 to the coefficient tail, it produces the formal-derivative coefficients in one cons walk.

                                                              Equations
                                                              Instances For
                                                                noncomputable def Hex.DensePoly.derivative {R : Type u} [Zero R] [DecidableEq R] [NatCast R] [Mul R] (p : DensePoly R) :

                                                                Formal derivative. The coefficient of x^i becomes (i + 1) * a_(i+1).

                                                                Kernel-facing specification: one cons walk of the coefficient tail. Compiled code uses Hex.DensePoly.derivativeImpl, the value-equal Array.ofFn loop selected by Hex.DensePoly.derivative_eq_impl.

                                                                Equations
                                                                Instances For

                                                                  Runtime implementation of derivative: one Array.ofFn allocation (value-equal to derivative by derivative_eq_impl, registered @[csimp]).

                                                                  Equations
                                                                  Instances For

                                                                    The reference derivative and the Array.ofFn runtime loop compute the same polynomial.

                                                                    @[csimp]

                                                                    Register the Array.ofFn loop as the compiled implementation of derivative.

                                                                    The derivative stores at most one fewer coefficient than its input.

                                                                    theorem Hex.DensePoly.coeff_add {R : Type u} [Zero R] [DecidableEq R] [Add R] (p q : DensePoly R) (n : Nat) (hzero : Zero.zero + Zero.zero = Zero.zero) :
                                                                    (p + q).coeff n = p.coeff n + q.coeff n

                                                                    Coefficient law for addition. The explicit zero law is needed because the generic Add/Zero interface does not imply 0 + 0 = 0.

                                                                    @[simp]
                                                                    theorem Hex.DensePoly.coeff_add_semiring {S : Type u} [Zero S] [Add S] [Lean.Grind.Semiring S] [DecidableEq S] (p q : DensePoly S) (n : Nat) (hzero : AddZeroLaw S := by infer_instance) :
                                                                    (p + q).coeff n = p.coeff n + q.coeff n

                                                                    Semiring-specialized coefficient law for addition.

                                                                    theorem Hex.DensePoly.scale_add {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] (a : S) (p q : DensePoly S) :
                                                                    scale a (p + q) = scale a p + scale a q

                                                                    Scaling distributes over polynomial addition.

                                                                    theorem Hex.DensePoly.coeff_sub {R : Type u} [Zero R] [DecidableEq R] [Sub R] (p q : DensePoly R) (n : Nat) (hzero : Zero.zero - Zero.zero = Zero.zero) :
                                                                    (p - q).coeff n = p.coeff n - q.coeff n

                                                                    Coefficient law for subtraction. The explicit zero law is needed because the generic Sub/Zero interface does not imply 0 - 0 = 0.

                                                                    @[simp]
                                                                    theorem Hex.DensePoly.coeff_sub_ring {S : Type u} [Zero S] [Sub S] [Lean.Grind.Ring S] [DecidableEq S] (p q : DensePoly S) (n : Nat) (hzero : SubZeroLaw S := by infer_instance) :
                                                                    (p - q).coeff n = p.coeff n - q.coeff n

                                                                    Ring-specialized coefficient law for subtraction.

                                                                    theorem Hex.DensePoly.coeff_neg {R : Type u} [Zero R] [DecidableEq R] [Sub R] (p : DensePoly R) (n : Nat) (hzero : Zero.zero - Zero.zero = Zero.zero) :
                                                                    (-p).coeff n = 0 - p.coeff n

                                                                    Coefficient law for negation, expressed through subtraction from zero. The explicit zero law is inherited from the generic subtraction coefficient theorem.

                                                                    @[simp]
                                                                    theorem Hex.DensePoly.coeff_neg_ring {S : Type u} [Zero S] [Sub S] [Neg S] [Lean.Grind.Ring S] [DecidableEq S] (p : DensePoly S) (n : Nat) (hsub : SubZeroLaw S := by infer_instance) (hneg : ZeroSubNegLaw S := by infer_instance) :
                                                                    (-p).coeff n = -p.coeff n

                                                                    Ring-specialized coefficient law for negation.

                                                                    @[simp]

                                                                    Semiring-specialized right zero law for dense polynomial addition.

                                                                    @[simp]

                                                                    Semiring-specialized left zero law for dense polynomial addition.

                                                                    @[simp]

                                                                    Ring-specialized right zero law for dense polynomial subtraction.

                                                                    @[simp]

                                                                    Ring-specialized left zero law for dense polynomial subtraction.

                                                                    @[simp]

                                                                    Ring-specialized negation of the zero dense polynomial.

                                                                    @[simp]
                                                                    theorem Hex.DensePoly.eval_zero {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (x : R) :
                                                                    eval 0 x = 0

                                                                    Horner evaluation sends the zero dense polynomial to 0.

                                                                    theorem Hex.DensePoly.eval_add {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p q : DensePoly R) (x : R) (hzero_add : Zero.zero + Zero.zero = Zero.zero) (hzero_horner : Zero.zero * x + Zero.zero = Zero.zero) (hstep : ∀ (a b c d : R), (a + b) * x + (c + d) = a * x + c + (b * x + d)) :
                                                                    (p + q).eval x = p.eval x + q.eval x

                                                                    Evaluation law for addition. The explicit laws package the zero-preservation and one-step Horner distributivity needed by the generic Add/Mul interface.

                                                                    @[simp]
                                                                    theorem Hex.DensePoly.eval_add_semiring {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] (p q : DensePoly S) (x : S) :
                                                                    (p + q).eval x = p.eval x + q.eval x

                                                                    Semiring-specialized evaluation law for addition.

                                                                    theorem Hex.DensePoly.eval_sub {R : Type u} [Zero R] [DecidableEq R] [Sub R] [Add R] [Mul R] (p q : DensePoly R) (x : R) (hzero_sub : Zero.zero - Zero.zero = Zero.zero) (hzero_horner : Zero.zero * x + Zero.zero = Zero.zero) (hstep : ∀ (a b c d : R), (a - b) * x + (c - d) = a * x + c - (b * x + d)) :
                                                                    (p - q).eval x = p.eval x - q.eval x

                                                                    Evaluation law for subtraction. The explicit laws package the zero-preservation and one-step Horner distributivity needed by the generic Sub/Mul interface.

                                                                    @[simp]
                                                                    theorem Hex.DensePoly.eval_sub_ring {S : Type u} [Lean.Grind.Ring S] [DecidableEq S] (p q : DensePoly S) (x : S) :
                                                                    (p - q).eval x = p.eval x - q.eval x

                                                                    Ring-specialized evaluation law for subtraction.

                                                                    theorem Hex.DensePoly.eval_neg {R : Type u} [Zero R] [DecidableEq R] [Sub R] [Add R] [Mul R] (p : DensePoly R) (x : R) (hzero_sub : Zero.zero - Zero.zero = Zero.zero) (hzero_horner : Zero.zero * x + Zero.zero = Zero.zero) (hstep : ∀ (a b c d : R), (a - b) * x + (c - d) = a * x + c - (b * x + d)) :
                                                                    (-p).eval x = Zero.zero - p.eval x

                                                                    Evaluation law for negation, expressed through subtraction from zero.

                                                                    @[simp]
                                                                    theorem Hex.DensePoly.eval_neg_ring {S : Type u} [Lean.Grind.Ring S] [DecidableEq S] (p : DensePoly S) (x : S) (hneg : ZeroSubNegLaw S := by infer_instance) :
                                                                    (-p).eval x = -p.eval x

                                                                    Ring-specialized evaluation law for negation.

                                                                    theorem Hex.DensePoly.eval_C {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (c x : R) (hzero_mul : Zero.zero * x = Zero.zero) (hzero_add : Zero.zero + c = c) :
                                                                    (C c).eval x = c

                                                                    Evaluation of a constant polynomial. The explicit zero laws are needed because the generic Add/Mul/Zero interfaces do not provide algebraic simplification rules.

                                                                    @[simp]
                                                                    theorem Hex.DensePoly.eval_C_semiring {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] (c x : S) :
                                                                    (C c).eval x = c

                                                                    Semiring-specialized evaluation law for constants. This packages the zero-multiplication and zero-addition laws needed by the generic eval_C.

                                                                    @[simp]
                                                                    theorem Hex.DensePoly.eval_monomial_semiring {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] (n : Nat) (c x : S) :
                                                                    (monomial n c).eval x = c * x ^ n

                                                                    Semiring-specialized evaluation law for monomials.

                                                                    @[simp]

                                                                    The formal derivative of the zero polynomial is zero.

                                                                    theorem Hex.DensePoly.coeff_derivative {R : Type u} [Zero R] [DecidableEq R] [NatCast R] [Mul R] (p : DensePoly R) (n : Nat) (hzero : ↑(n + 1) * Zero.zero = Zero.zero) :
                                                                    p.derivative.coeff n = ↑(n + 1) * p.coeff (n + 1)

                                                                    Characterising coefficient law for the formal derivative: the coefficient of x^n in derivative p is (n + 1) * p.coeff (n + 1). The explicit zero law ((n + 1 : Nat) : R) * 0 = 0 is needed because the generic NatCast/Mul/Zero interface does not guarantee it, mirroring the hypothesis on Hex.DensePoly.coeff_scale.

                                                                    @[simp]

                                                                    Semiring-specialized coefficient law for the formal derivative, registered as a normalizing rewrite because semirings provide the required a * 0 = 0 law.

                                                                    @[simp]

                                                                    The formal derivative of a constant polynomial is zero over a semiring.

                                                                    @[simp]

                                                                    The formal derivative of a degree-zero monomial is zero over a semiring.

                                                                    The formal derivative of c * x^(n + 1) is (n + 1) * c * x^n over a semiring.