Documentation

HexSparsePoly.Arith

@[irreducible]
def Hex.SparsePoly.mergeWith {R : Type u} [Zero R] [DecidableEq R] (fl fr : RR) (fb : RRR) :
List (Nat × R)List (Nat × R)List (Nat × R)

Linear merge of two sorted term lists: fl maps a coefficient present only on the left, fr one present only on the right, fb combines a collision, and zero results are dropped. add and sub are instances.

Equations
Instances For
    theorem Hex.SparsePoly.exp_mem_mergeWith {R : Type u} [Zero R] [DecidableEq R] {fl fr : RR} {fb : RRR} {l₁ l₂ : List (Nat × R)} {t : Nat × R} (ht : t mergeWith fl fr fb l₁ l₂) :
    ( (u : Nat × R), u l₁ t.fst = u.fst) (u : Nat × R), u l₂ t.fst = u.fst

    Every exponent stored by the merge comes from one of the inputs.

    theorem Hex.SparsePoly.mergeWith_canonical {R : Type u} [Zero R] [DecidableEq R] {fl fr : RR} {fb : RRR} {l₁ l₂ : List (Nat × R)} (hs₁ : List.Pairwise (fun (a b : Nat × R) => a.fst < b.fst) l₁) (hs₂ : List.Pairwise (fun (a b : Nat × R) => a.fst < b.fst) l₂) :
    List.Pairwise (fun (a b : Nat × R) => a.fst < b.fst) (mergeWith fl fr fb l₁ l₂) ∀ (t : Nat × R), t mergeWith fl fr fb l₁ l₂t.snd 0

    The merge of two canonical term lists is canonical.

    theorem Hex.SparsePoly.coeffList_filterMap_map {R : Type u} [Zero R] [DecidableEq R] {f : RR} {l : List (Nat × R)} (hs : List.Pairwise (fun (a b : Nat × R) => a.fst < b.fst) l) (hf0 : f 0 = 0) (e : Nat) :
    coeffList (List.filterMap (fun (t : Nat × R) => if f t.snd = 0 then none else some (t.fst, f t.snd)) l) e = f (coeffList l e)

    Coefficient description of the zero-filtered coefficient map used by the merge's one-sided cases.

    theorem Hex.SparsePoly.coeffList_mergeWith {R : Type u} [Zero R] [DecidableEq R] {fl fr : RR} {fb : RRR} {l₁ l₂ : List (Nat × R)} (hs₁ : List.Pairwise (fun (a b : Nat × R) => a.fst < b.fst) l₁) (hs₂ : List.Pairwise (fun (a b : Nat × R) => a.fst < b.fst) l₂) (hb00 : fb 0 0 = 0) (hbl : ∀ (x : R), fb x 0 = fl x) (hbr : ∀ (y : R), fb 0 y = fr y) (e : Nat) :
    coeffList (mergeWith fl fr fb l₁ l₂) e = fb (coeffList l₁ e) (coeffList l₂ e)

    Coefficient description of the merge. The three compatibility hypotheses identify the structural choices with the pointwise fb against an absent side's 0.

    theorem Hex.SparsePoly.pairwise_toList {R : Type u} [Zero R] [DecidableEq R] (s : SparsePoly R) :
    List.Pairwise (fun (a b : Nat × R) => a.fst < b.fst) s.terms.toList

    The canonical-form invariant, list-level: exponents strictly increase.

    theorem Hex.SparsePoly.nonzero_toList {R : Type u} [Zero R] [DecidableEq R] (s : SparsePoly R) (t : Nat × R) :
    t s.terms.toListt.snd 0

    The canonical-form invariant, list-level: no stored coefficient is zero.

    theorem Hex.SparsePoly.mem_support_iff {R : Type u} [Zero R] [DecidableEq R] (s : SparsePoly R) (e : Nat) :

    The stored exponents are exactly the exponents with a nonzero coefficient. Uses both canonical-form invariants: strict increase makes the stored coefficient the coefficient, and zero-freedom makes it nonzero.

    def Hex.SparsePoly.ofCanonicalList {R : Type u} [Zero R] [DecidableEq R] (l : List (Nat × R)) (hs : List.Pairwise (fun (a b : Nat × R) => a.fst < b.fst) l) (hnz : ∀ (t : Nat × R), t lt.snd 0) :

    Package a canonical term list as a polynomial.

    Equations
    Instances For
      @[simp]
      theorem Hex.SparsePoly.coeff_ofCanonicalList {R : Type u} [Zero R] [DecidableEq R] (l : List (Nat × R)) (hs : List.Pairwise (fun (a b : Nat × R) => a.fst < b.fst) l) (hnz : ∀ (t : Nat × R), t lt.snd 0) (e : Nat) :
      (ofCanonicalList l hs hnz).coeff e = coeffList l e

      Packaging a canonical term list keeps its list coefficients.

      def Hex.SparsePoly.mapTerms {R : Type u} [Zero R] [DecidableEq R] (g : NatNat) (f : NatRR) (l : List (Nat × R)) :
      List (Nat × R)

      Map exponents and coefficients over a term list, dropping the terms whose new coefficient is zero. neg, scale, and mulMonomial are instances (with the identity exponent map or a shift).

      Equations
      Instances For
        theorem Hex.SparsePoly.exp_mem_mapTerms {R : Type u} [Zero R] [DecidableEq R] {g : NatNat} {f : NatRR} {l : List (Nat × R)} {t : Nat × R} (ht : t mapTerms g f l) :
        (u : Nat × R), u l t.fst = g u.fst

        Every exponent stored by the map is the image of a stored one.

        theorem Hex.SparsePoly.mapTerms_canonical {R : Type u} [Zero R] [DecidableEq R] {g : NatNat} {f : NatRR} {l : List (Nat × R)} (hs : List.Pairwise (fun (a b : Nat × R) => a.fst < b.fst) l) (hmono : ∀ (a : Nat × R), a l∀ (b : Nat × R), b la.fst < b.fstg a.fst < g b.fst) :
        List.Pairwise (fun (a b : Nat × R) => a.fst < b.fst) (mapTerms g f l) ∀ (t : Nat × R), t mapTerms g f lt.snd 0

        The map of a canonical term list along a strictly monotone exponent map is canonical.

        theorem Hex.SparsePoly.coeffList_mapTerms_apply {R : Type u} [Zero R] [DecidableEq R] {g : NatNat} {f : NatRR} {l : List (Nat × R)} {e : Nat} (hs : List.Pairwise (fun (a b : Nat × R) => a.fst < b.fst) l) (hinj : ∀ (u : Nat × R), u lg u.fst = g eu.fst = e) (hf0 : f e 0 = 0) :
        coeffList (mapTerms g f l) (g e) = f e (coeffList l e)

        Coefficient of the mapped list at a mapped exponent, for an exponent map injective into the stored exponents.

        theorem Hex.SparsePoly.coeffList_mapTerms_of_ne {R : Type u} [Zero R] [DecidableEq R] {g : NatNat} {f : NatRR} {l : List (Nat × R)} {x : Nat} (hx : ∀ (u : Nat × R), u lg u.fst x) :
        coeffList (mapTerms g f l) x = 0

        The mapped list stores nothing outside the image of the exponent map.

        def Hex.SparsePoly.add {R : Type u} [Zero R] [DecidableEq R] [Add R] (s t : SparsePoly R) :

        Add two sparse polynomials by a linear merge of the sorted term arrays, O(s + t): sums at a matching exponent, and a zero sum stores nothing.

        Equations
        Instances For
          @[instance_reducible]
          instance Hex.SparsePoly.instAdd {R : Type u} [Zero R] [DecidableEq R] [Add R] :
          Equations
          theorem Hex.SparsePoly.coeff_add' {R : Type u} [Zero R] [DecidableEq R] [Add R] (h00 : 0 + 0 = 0) (hl : ∀ (x : R), x + 0 = x) (hr : ∀ (y : R), 0 + y = y) (s t : SparsePoly R) (e : Nat) :
          (s + t).coeff e = s.coeff e + t.coeff e

          Coefficient law for add, under the pointwise hypotheses it needs; the Lean.Grind.Semiring form is coeff_add.

          @[simp]
          theorem Hex.SparsePoly.coeff_add {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] (s t : SparsePoly S) (e : Nat) :
          (s + t).coeff e = s.coeff e + t.coeff e

          Grind-classes form of coeff_add': addition is coefficientwise.

          def Hex.SparsePoly.sub {R : Type u} [Zero R] [DecidableEq R] [Sub R] (s t : SparsePoly R) :

          Subtract two sparse polynomials by a linear merge, O(s + t).

          Equations
          Instances For
            @[instance_reducible]
            instance Hex.SparsePoly.instSub {R : Type u} [Zero R] [DecidableEq R] [Sub R] :
            Equations
            theorem Hex.SparsePoly.coeff_sub' {R : Type u} [Zero R] [DecidableEq R] [Sub R] (h00 : 0 - 0 = 0) (hl : ∀ (x : R), x - 0 = x) (s t : SparsePoly R) (e : Nat) :
            (s - t).coeff e = s.coeff e - t.coeff e

            Coefficient law for sub, under the pointwise hypotheses it needs; the Lean.Grind.Ring form is coeff_sub.

            @[simp]
            theorem Hex.SparsePoly.coeff_sub {S : Type u} [Lean.Grind.Ring S] [DecidableEq S] (s t : SparsePoly S) (e : Nat) :
            (s - t).coeff e = s.coeff e - t.coeff e

            Grind-classes form of coeff_sub': subtraction is coefficientwise.

            def Hex.SparsePoly.neg {R : Type u} [Zero R] [DecidableEq R] [Sub R] (s : SparsePoly R) :

            Negate a sparse polynomial: subtraction from zero, compiled as one filtered coefficient map. Over a ring the exponents and the term count are unchanged; [Sub R] alone does not supply that, so the zero filter stays.

            Equations
            Instances For
              @[instance_reducible]
              Equations
              theorem Hex.SparsePoly.coeff_neg' {R : Type u} [Zero R] [DecidableEq R] [Sub R] (h00 : 0 - 0 = 0) (s : SparsePoly R) (e : Nat) :
              (-s).coeff e = 0 - s.coeff e

              Coefficient law for neg, under the pointwise hypothesis it needs; the Lean.Grind.Ring form is coeff_neg.

              @[simp]
              theorem Hex.SparsePoly.coeff_neg {S : Type u} [Lean.Grind.Ring S] [DecidableEq S] (s : SparsePoly S) (e : Nat) :
              (-s).coeff e = 0 - s.coeff e

              Grind-classes form of coeff_neg': negation is coefficientwise.

              def Hex.SparsePoly.scale {R : Type u} [Zero R] [DecidableEq R] [Mul R] (c : R) (s : SparsePoly R) :

              Multiply every coefficient by c, dropping the products that vanish: c = 0 gives the zero polynomial, and a zero divisor c can delete an interior term while leaving its neighbours.

              Equations
              Instances For
                theorem Hex.SparsePoly.coeff_scale' {R : Type u} [Zero R] [DecidableEq R] [Mul R] (hc0 : ∀ (c : R), c * 0 = 0) (c : R) (s : SparsePoly R) (e : Nat) :
                (scale c s).coeff e = c * s.coeff e

                Coefficient law for scale, under the pointwise hypothesis it needs; the Lean.Grind.Semiring form is coeff_scale.

                @[simp]
                theorem Hex.SparsePoly.coeff_scale {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] (c : S) (s : SparsePoly S) (e : Nat) :
                (scale c s).coeff e = c * s.coeff e

                Grind-classes form of coeff_scale': scaling multiplies each coefficient.

                def Hex.SparsePoly.mulMonomial {R : Type u} [Zero R] [DecidableEq R] [Mul R] (e : Nat) (c : R) (s : SparsePoly R) :

                Multiply by the monomial c · x^e: add e to every exponent and multiply every coefficient by c. The exponent shift is strictly monotone, so the only canonicalisation is the zero filter. This is the cheap shift mul is built from, O(s).

                Equations
                Instances For
                  theorem Hex.SparsePoly.coeff_mulMonomial' {R : Type u} [Zero R] [DecidableEq R] [Mul R] (hc0 : ∀ (c : R), c * 0 = 0) (s : SparsePoly R) (e : Nat) (c : R) (f : Nat) :
                  (mulMonomial e c s).coeff f = if e f then c * s.coeff (f - e) else 0

                  Coefficient law for mulMonomial, under the pointwise hypothesis it needs; the Lean.Grind.Semiring form is coeff_mulMonomial.

                  @[simp]
                  theorem Hex.SparsePoly.coeff_mulMonomial {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] (s : SparsePoly S) (e : Nat) (c : S) (f : Nat) :
                  (mulMonomial e c s).coeff f = if e f then c * s.coeff (f - e) else 0

                  Grind-classes form of coeff_mulMonomial': a monomial multiple shifts and scales the coefficients.

                  def Hex.SparsePoly.mul {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (s t : SparsePoly R) :

                  Multiply two sparse polynomials: the canonicalised pairwise product. Every pair of exponents contributes, exponent sums collide freely, and ofTerms combines the collisions and drops what cancels. The pairwise products are built through the term Lists so the kernel can reduce this specification (Array.flatMap stalls kernel reduction; the value is unchanged). The @[csimp] implementation is selected by the Phase-4 sparse-multiplication bench family; until then compiled code runs this specification through ofTerms's sort-and-combine twin.

                  Equations
                  Instances For
                    @[instance_reducible]
                    instance Hex.SparsePoly.instMulOfAdd {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] :
                    Equations

                    Tree accumulator for mulImpl: fold every pairwise product into an Std.ExtTreeMap keyed on the exponent sum, replaying addCoeff per key so the accumulated value is exactly the specification's input-order fold. A stored 0 encodes an exponent whose partial sum cancelled and is dropped at read-out.

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

                      Runtime implementation of mul, selected by the Phase-4 sparse-multiplication bench family (see the SPEC's measured note): the ExtTreeMap accumulation, which beat sort-and-combine on both collision shapes and the Johnson heap merge everywhere (value-equal to mul by mul_eq_impl, registered @[csimp]).

                      Equations
                      Instances For
                        theorem Hex.SparsePoly.mul_eq_mulImpl {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (s t : SparsePoly R) :
                        s.mul t = s.mulImpl t

                        The specification and the tree accumulation compute the same polynomial, with no algebra assumed: the tree replays the addCoeff steps per key in the specification's input order.

                        @[csimp]

                        Register the tree accumulation as the compiled implementation of mul.

                        @[irreducible]
                        def Hex.SparsePoly.pow {R : Type u} [Zero R] [DecidableEq R] [One R] [Add R] [Mul R] (s : SparsePoly R) (n : Nat) :

                        Raise to a power by binary powering over mul. A caller wanting f(x^k) should use substPow, never pow: the cost difference is the whole reason this library exists.

                        Equations
                        Instances For
                          @[instance_reducible]

                          Divisibility by existence of a cofactor, matching the DensePoly convention.

                          Equations
                          theorem Hex.SparsePoly.dvd_def {R : Type u} [Zero R] [DecidableEq R] [Add R] [Mul R] (p q : SparsePoly R) :
                          p q (r : SparsePoly R), q = p * r

                          Divisibility unfolds to a cofactor witness.

                          theorem Hex.SparsePoly.add_comm {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] (s t : SparsePoly S) :
                          s + t = t + s

                          Addition is commutative.

                          theorem Hex.SparsePoly.add_assoc {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] (s t u : SparsePoly S) :
                          s + t + u = s + (t + u)

                          Addition is associative.

                          @[simp]

                          Zero is a right identity for addition.

                          @[simp]

                          Zero is a left identity for addition.