The is_poly predicate #
witt_vector.is_poly is a (type-valued) predicate on functions f : Π R, 𝕎 R → 𝕎 R.
It asserts that there is a family of polynomials φ : ℕ → mv_polynomial ℕ ℤ,
such that the nth coefficient of f x is equal to φ n evaluated on the coefficients of x.
Many operations on Witt vectors satisfy this predicate (or an analogue for higher arity functions).
We say that such a function f is a polynomial function.
The power of satisfying this predicate comes from is_poly.ext.
It shows that if φ and ψ witness that f and g are polynomial functions,
then f = g not merely when φ = ψ, but in fact it suffices to prove
∀ n, bind₁ φ (witt_polynomial p _ n) = bind₁ ψ (witt_polynomial p _ n)
(in other words, when evaluating the Witt polynomials on φ and ψ, we get the same values)
which will then imply φ = ψ and hence f = g.
Even though this sufficient condition looks somewhat intimidating,
it is rather pleasant to check in practice;
more so than direct checking of φ = ψ.
In practice, we apply this technique to show that the composition of witt_vector.frobenius
and witt_vector.verschiebung is equal to multiplication by p.
Main declarations #
witt_vector.is_poly,witt_vector.is_poly₂: two predicates that assert that a unary/binary function on Witt vectors is polynomial in the coefficients of the input values.witt_vector.is_poly.ext,witt_vector.is_poly₂.ext: two polynomial functions are equal if their families of polynomials are equal after evaluating the Witt polynomials on them.witt_vector.is_poly.comp(+ many variants) show that unary/binary compositions of polynomial functions are polynomial.witt_vector.id_is_poly,witt_vector.neg_is_poly,witt_vector.add_is_poly₂,witt_vector.mul_is_poly₂: several well-known operations are polynomial functions (for Verschiebung, Frobenius, and multiplication byp, see their respective files).
On higher arity analogues #
Ideally, there should be a predicate is_polyₙ for functions of higher arity,
together with is_polyₙ.comp that shows how such functions compose.
Since mathlib does not have a library on composition of higher arity functions,
we have only implemented the unary and binary variants so far.
Nullary functions (a.k.a. constants) are treated
as constant functions and fall under the unary case.
Tactics #
There are important metaprograms defined in this file:
the tactics ghost_simp and ghost_calc and the attributes @[is_poly] and @[ghost_simps].
These are used in combination to discharge proofs of identities between polynomial functions.
Any atomic proof of is_poly or is_poly₂ (i.e. not taking additional is_poly arguments)
should be tagged as @[is_poly].
Any lemma doing "ring equation rewriting" with polynomial functions should be tagged
@[ghost_simps], e.g.
@[ghost_simps]
lemma bind₁_frobenius_poly_witt_polynomial (n : ℕ) :
bind₁ (frobenius_poly p) (witt_polynomial p ℤ n) = (witt_polynomial p ℤ (n+1))
Proofs of identities between polynomial functions will often follow the pattern
begin
ghost_calc _,
<minor preprocessing>,
ghost_simp
end
References #
- poly : ∃ (φ : ℕ → mv_polynomial ℕ ℤ), ∀ ⦃R : Type ?⦄ [_inst_3 : comm_ring R] (x : witt_vector p R), (f x).coeff = λ (n : ℕ), ⇑(mv_polynomial.aeval x.coeff) (φ n)
A function f : Π R, 𝕎 R → 𝕎 R that maps Witt vectors to Witt vectors over arbitrary base rings
is said to be polynomial if there is a family of polynomials φₙ over ℤ such that the nth
coefficient of f x is given by evaluating φₙ at the coefficients of x.
See also witt_vector.is_poly₂ for the binary variant.
The ghost_calc tactic treats is_poly as a type class,
and the @[is_poly] attribute derives certain specialized composition instances
for declarations of type is_poly f.
For the most part, users are not expected to treat is_poly as a class.
Instances of this typeclass
- witt_vector.id_is_poly
- witt_vector.id_is_poly_i'
- witt_vector.neg_is_poly.comp_i
- witt_vector.zero_is_poly
- witt_vector.one_is_poly
- witt_vector.add_is_poly₂.comp_diag
- witt_vector.mul_is_poly₂.comp_diag
- witt_vector.select_is_poly.comp_i
- witt_vector.frobenius_fun_is_poly.comp_i
- witt_vector.frobenius_is_poly.comp_i
- witt_vector.verschiebung_fun_is_poly.comp_i
- witt_vector.verschiebung_is_poly.comp_i
- witt_vector.mul_n_is_poly.comp_i
Instances of other typeclasses for witt_vector.is_poly
The identity function on Witt vectors is a polynomial function.
Equations
- witt_vector.is_poly.inhabited p = {default := _}
The composition of polynomial functions is polynomial.
- poly : ∃ (φ : ℕ → mv_polynomial (fin 2 × ℕ) ℤ), ∀ ⦃R : Type ?⦄ [_inst_3 : comm_ring R] (x y : witt_vector p R), (f x y).coeff = λ (n : ℕ), witt_vector.peval (φ n) ![x.coeff, y.coeff]
A binary function f : Π R, 𝕎 R → 𝕎 R → 𝕎 R on Witt vectors
is said to be polynomial if there is a family of polynomials φₙ over ℤ such that the nth
coefficient of f x y is given by evaluating φₙ at the coefficients of x and y.
See also witt_vector.is_poly for the unary variant.
The ghost_calc tactic treats is_poly₂ as a type class,
and the @[is_poly] attribute derives certain specialized composition instances
for declarations of type is_poly₂ f.
For the most part, users are not expected to treat is_poly₂ as a class.
Instances of this typeclass
- witt_vector.neg_is_poly.comp₂_i
- witt_vector.add_is_poly₂.comp₂_i
- witt_vector.mul_is_poly₂.comp₂_i
- witt_vector.select_is_poly.comp₂_i
- witt_vector.frobenius_fun_is_poly.comp₂_i
- witt_vector.frobenius_is_poly.comp₂_i
- witt_vector.verschiebung_fun_is_poly.comp₂_i
- witt_vector.verschiebung_is_poly.comp₂_i
- witt_vector.mul_n_is_poly.comp₂_i
Instances of other typeclasses for witt_vector.is_poly₂
The composition of polynomial functions is polynomial.
The composition of a polynomial function with a binary polynomial function is polynomial.
The diagonal λ x, f x x of a polynomial function f is polynomial.
The @[is_poly] attribute #
This attribute is used to derive specialized composition instances
for is_poly and is_poly₂ declarations.
is_poly instances #
These are not declared as instances at the top level,
but the @[is_poly] attribute adds instances based on each one.
Users are expected to use the non-instance versions manually.
The additive negation is a polynomial function on Witt vectors.
The function that is constantly zero on Witt vectors is a polynomial function.
The coefficients of 1 : 𝕎 R as polynomials.
Equations
- witt_vector.one_poly n = ite (n = 0) 1 0
The function that is constantly one on Witt vectors is a polynomial function.
Addition of Witt vectors is a polynomial function.
Multiplication of Witt vectors is a polynomial function.
Equations
The composition of a binary polynomial function with a unary polynomial function in the first argument is polynomial.
The composition of a binary polynomial function with a unary polynomial function in the second argument is polynomial.