Documentation

HexSparsePoly.Dense

def Hex.SparsePoly.termsBound {R : Type u} (ts : Array (Nat × R)) :

One more than the largest exponent of a term array (0 when empty): the number of coefficients its dense form stores.

Equations
Instances For
    theorem Hex.SparsePoly.le_foldl_max {R : Type u} (l : List (Nat × R)) (init : Nat) :
    init List.foldl (fun (m : Nat) (t : Nat × R) => max m (t.fst + 1)) init l

    The bound fold dominates its initial value.

    theorem Hex.SparsePoly.exp_lt_foldl_max {R : Type u} {l : List (Nat × R)} {t : Nat × R} (ht : t l) (init : Nat) :
    t.fst < List.foldl (fun (m : Nat) (t : Nat × R) => max m (t.fst + 1)) init l

    Every stored exponent is below the bound.

    theorem Hex.SparsePoly.foldl_max_le {R : Type u} {l : List (Nat × R)} {n : Nat} (init : Nat) (h0 : init n) (h : ∀ (t : Nat × R), t lt.fst < n) :
    List.foldl (fun (m : Nat) (t : Nat × R) => max m (t.fst + 1)) init l n

    The bound is least among exponent bounds at or above its initial value.

    theorem Hex.SparsePoly.size_foldl_set {R : Type u} (l : List (Nat × R)) (base : Array R) :
    (List.foldl (fun (acc : Array R) (t : Nat × R) => acc.setIfInBounds t.fst t.snd) base l).size = base.size

    Writing a term list into an array does not change its size.

    theorem Hex.SparsePoly.getD_foldl_set {R : Type u} [Zero R] {l : List (Nat × R)} (hs : List.Pairwise (fun (a b : Nat × R) => a.fst < b.fst) l) (base : Array R) (hbound : ∀ (t : Nat × R), t lt.fst < base.size) (i : Nat) :
    (List.foldl (fun (acc : Array R) (t : Nat × R) => acc.setIfInBounds t.fst t.snd) base l).getD i 0 = if (t : Nat × R), t l t.fst = i then coeffList l i else base.getD i 0

    Writing a sorted, in-bounds term list into an array puts each coefficient at its exponent and touches nothing else.

    def Hex.SparsePoly.coeffsOfTerms {R : Type u} [Zero R] (ts : Array (Nat × R)) :

    Write each term of an arbitrary term array into a coefficient array sized by the largest exponent. A conversion, not a canonicaliser: with duplicate exponents the last write wins, which is what makes the round-trip hypotheses below necessary.

    Equations
    Instances For

      Keep the nonzero coefficients of a coefficient list with their indices, starting at index i. Kernel-facing walk shared by termsOfCoeffs and ofDense.

      Equations
      Instances For

        Keep the nonzero coefficients of a coefficient array with their indices.

        Equations
        Instances For
          theorem Hex.SparsePoly.exp_mem_termsOfCoeffsList {R : Type u} [Zero R] [DecidableEq R] {l : List R} {i : Nat} {t : Nat × R} (ht : t termsOfCoeffsList i l) :
          i t.fst t.fst < i + l.length

          Every index stored by the walk is at least the starting index and within the list.

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

          The walk emits a canonical term list.

          theorem Hex.SparsePoly.coeffList_termsOfCoeffsList {R : Type u} [Zero R] [DecidableEq R] (l : List R) (i e : Nat) :
          coeffList (termsOfCoeffsList i l) (i + e) = l.getD e 0

          The walk stores exactly the nonzero coefficients: its coefficient at i + e is the list's value at e.

          theorem Hex.SparsePoly.coeffList_termsOfCoeffsList_of_lt {R : Type u} [Zero R] [DecidableEq R] (l : List R) {i f : Nat} (hf : f < i) :

          The walk stores nothing below its starting index.

          Convert to the dense representation: allocate degree + 1 coefficients and write each stored term into its slot, O(n) in the degree whatever the term count. The one operation here whose cost is not governed by the term count; no operation in this library is implemented through it.

          Equations
          Instances For
            @[simp]
            theorem Hex.SparsePoly.coeff_toDense {R : Type u} [Zero R] [DecidableEq R] (s : SparsePoly R) (e : Nat) :

            The conversion preserves every coefficient.

            noncomputable def Hex.SparsePoly.ofDense {R : Type u} [Zero R] [DecidableEq R] (p : DensePoly R) :

            Convert from the dense representation, keeping the nonzero coefficients with their indices.

            Kernel-facing specification (an ordered List walk); compiled code uses Hex.SparsePoly.ofDenseImpl, the value-equal array pass selected by Hex.SparsePoly.ofDense_eq_impl.

            Equations
            Instances For

              Array worker for ofDenseImpl: one indexed pass pushing the nonzero coefficients.

              Equations
              Instances For

                The array pass agrees with the kernel-facing list walk.

                Runtime implementation of ofDense: one array pass (value-equal to ofDense by ofDense_eq_impl, registered @[csimp]).

                Equations
                Instances For

                  The list walk and the array pass build the same polynomial.

                  @[csimp]

                  Register the array pass as the compiled implementation of ofDense.

                  @[simp]
                  theorem Hex.SparsePoly.coeff_ofDense {R : Type u} [Zero R] [DecidableEq R] (p : DensePoly R) (e : Nat) :
                  (ofDense p).coeff e = p.coeff e

                  The conversion preserves every coefficient.

                  theorem Hex.SparsePoly.toList_getD {R : Type u} (a : Array R) (i : Nat) (d : R) :
                  a.toList.getD i d = a.getD i d

                  getD on an array agrees with getD on its list.

                  theorem Hex.SparsePoly.getD_coeffsOfTerms {R : Type u} [Zero R] {ts : Array (Nat × R)} (hs : List.Pairwise (fun (a b : Nat × R) => a.fst < b.fst) ts.toList) (e : Nat) :

                  The dense image of a sorted term array stores exactly its coefficients.

                  The sparse image of a coefficient array stores exactly its coefficients.

                  Round trip through the dense coefficients: exact on canonical term arrays, and false without either half of the invariant (a stored zero vanishes, a duplicate is overwritten, unsorted input comes back sorted).

                  Round trip through the term list: exact on trailing-zero-free coefficient arrays, and false without DensePolyNormalized (a trailing zero is not reconstructed). It is DensePoly's own invariant that makes the sparse round trip exact.

                  @[simp]

                  Round trip on the bundled types, dense side out: unconditional, because the type carries its canonical form.

                  @[simp]

                  Round trip on the bundled types, sparse side out: unconditional, because DensePoly carries its trailing-zero-free form.

                  theorem Hex.SparsePoly.toDense_inj {R : Type u} [Zero R] [DecidableEq R] {s t : SparsePoly R} (h : s.toDense = t.toDense) :
                  s = t

                  The dense conversion is injective, which is how sparse identities are transported back from dense ones.

                  @[simp]

                  The conversion sends zero to zero.

                  @[simp]
                  theorem Hex.SparsePoly.toDense_one {R : Type u} [Zero R] [DecidableEq R] [One R] :

                  The conversion sends one to one.

                  @[simp]

                  The conversion sends monomials to dense monomials.

                  The conversion is additive.

                  The conversion commutes with negation.

                  The reverse conversion sends zero to zero.

                  theorem Hex.SparsePoly.ofDense_one {R : Type u} [Zero R] [DecidableEq R] [One R] :

                  The reverse conversion sends one to one.

                  The reverse conversion is additive.

                  The reverse conversion commutes with negation.

                  theorem Hex.SparsePoly.foldl_congr' {α : Type u_1} {β : Type u_2} {l : List α} {f g : βαβ} {i j : β} (hij : i = j) (hfg : ∀ (b : β) (a : α), a lf b a = g b a) :
                  List.foldl f i l = List.foldl g j l

                  Fold congruence pointwise on the folded function and initial value.

                  A fresh insertion is the inserted coefficient, with no algebra assumed.

                  theorem Hex.SparsePoly.coeff_foldl_add {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] {α : Type u_1} (l : List α) (g : αSparsePoly S) (init : SparsePoly S) (f : Nat) :
                  (List.foldl (fun (acc : SparsePoly S) (a : α) => acc + g a) init l).coeff f = List.foldl (fun (acc : S) (a : α) => acc + (g a).coeff f) (init.coeff f) l

                  Coefficients of a fold of sums, sparse side.

                  theorem Hex.SparsePoly.coeff_mul_foldl {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] (s t : SparsePoly S) (f : Nat) :
                  (s * t).coeff f = List.foldl (fun (acc : S) (a : Nat × S) => acc + (mulMonomial a.fst a.snd t).coeff f) 0 s.terms.toList

                  The pairwise-product coefficient, reorganised as a fold of mulMonomial coefficients over the left operand's terms.

                  theorem Hex.SparsePoly.mul_eq_foldl {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] (s t : SparsePoly S) :
                  s * t = List.foldl (fun (acc : SparsePoly S) (a : Nat × S) => acc + mulMonomial a.fst a.snd t) 0 s.terms.toList

                  The pairwise product is the fold of monomial multiples: the shape the dense transport consumes.

                  theorem Hex.SparsePoly.toDense_foldl_add {S : Type u} [Lean.Grind.Semiring S] [DecidableEq S] {α : Type u_1} (l : List α) (g : αSparsePoly S) (init : SparsePoly S) :
                  (List.foldl (fun (acc : SparsePoly S) (a : α) => acc + g a) init l).toDense = List.foldl (fun (acc : DensePoly S) (a : α) => acc + (g a).toDense) init.toDense l

                  The dense image of a fold of sums.

                  A fold of dense monomials at the stored terms rebuilds the dense image.

                  The dense image of a monomial multiple is the dense monomial product.

                  The conversion is multiplicative: the transported convolution. This is where coeff_mul and the multiplicative ring laws come from.

                  The multiplicative homomorphism, dense side in.

                  The convolution, by transport: multiplication agrees with the dense coefficient sum.

                  theorem Hex.SparsePoly.mul_assoc {S : Type u} [Lean.Grind.CommRing S] [DecidableEq S] (s t u : SparsePoly S) :
                  s * t * u = s * (t * u)

                  Multiplication is associative.

                  theorem Hex.SparsePoly.mul_comm {S : Type u} [Lean.Grind.CommRing S] [DecidableEq S] (s t : SparsePoly S) :
                  s * t = t * s

                  Multiplication is commutative.

                  @[simp]

                  One is a right identity for multiplication.

                  @[simp]

                  One is a left identity for multiplication.

                  @[simp]

                  Zero absorbs on the right of multiplication.

                  @[simp]

                  Zero absorbs on the left of multiplication.

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

                  Multiplication distributes over addition on the left.

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

                  Multiplication distributes over addition on the right.

                  @[simp]

                  The zeroth power is one.

                  The conversion respects scalar multiplication.

                  @[simp]

                  The conversion sends constants to constants.

                  theorem Hex.SparsePoly.scale_eq_C_mul {S : Type u} [Lean.Grind.CommRing S] [DecidableEq S] (c : S) (s : SparsePoly S) :
                  scale c s = C c * s

                  Scalar multiplication is multiplication by the constant.

                  theorem Hex.SparsePoly.monomial_mul_monomial {S : Type u} [Lean.Grind.CommRing S] [DecidableEq S] (a b : Nat) (c d : S) :
                  monomial a c * monomial b d = monomial (a + b) (c * d)

                  Sparse monomials multiply exponentwise, by transport.

                  theorem Hex.SparsePoly.pow_succ {S : Type u} [Lean.Grind.CommRing S] [DecidableEq S] (s : SparsePoly S) (n : Nat) :
                  s ^ (n + 1) = s * s ^ n

                  The power recurrence: with pow_zero this characterises the binary powering completely, and together with coeff_mul it is what the SPEC's coeff_pow obligation reduces to.

                  theorem Hex.SparsePoly.exp_le_back {R : Type u} [Zero R] [DecidableEq R] {s : SparsePoly R} {t : Nat × R} (hback : s.terms.back? = some t) (u : Nat × R) :
                  u s.terms.toListu.fst t.fst

                  On a sorted term list the last stored exponent dominates.

                  theorem Hex.SparsePoly.leadingCoeff_eq_coeff {R : Type u} [Zero R] [DecidableEq R] {s : SparsePoly R} {t : Nat × R} (hback : s.terms.back? = some t) :

                  The leading coefficient is the coefficient at the last stored exponent.

                  theorem Hex.SparsePoly.size_toDense_eq {R : Type u} [Zero R] [DecidableEq R] {s : SparsePoly R} {t : Nat × R} (hback : s.terms.back? = some t) :

                  The dense image stores exactly degree + 1 coefficients.

                  @[simp]

                  The degree boundary transports: a leading coefficient is a coefficient at the degree, and coeff_toDense alone says nothing about where the degree is.

                  @[simp]

                  The leading coefficient transports through the dense conversion.

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

                  A sparse polynomial is monic when its leading coefficient is 1, matching the DensePoly convention.

                  Equations
                  Instances For
                    @[simp]

                    Monicity transports through the dense conversion.