poly design
This page explains why evaluating a luna-poly polynomial on dual numbers
yields its derivative, what the dense and sparse evaluation orders compute,
how accurate the result is, and why the bridge is limited to one variable.
Design goal
Give luna-poly users the value and the derivative of a polynomial at a
point with no new polynomial representation and no symbolic step, by reusing
the evaluation algorithms luna-poly already has.
Mathematical background
Evaluation over dual numbers is the derivative
For over a commutative semiring , the dual design shows
where means added times. The identity is algebraic, so it holds exactly for integer polynomials and up to rounding for floating-point ones; it needs neither limits nor division.
Horner’s rule on dual numbers
DensePolynomial::eval computes , for
, and returns . With , the
lifted coefficients , and ,
the dual product and sum give
For this is the classical scheme that evaluates a polynomial and its derivative together.11 D. E. Knuth, The Art of Computer Programming, vol. 2, 3rd ed., section 4.6.4. By induction and , so and .
Sparse terms by powering
SparsePolynomial::eval sums over the stored terms and computes
by binary powering. On dual numbers every product applies the product
rule, so becomes (the binomial
identity of the dual design), and the sum of the terms gives again.
Design decisions
Evaluate instead of differentiating symbolically
Problem. Users need at points.
Options. Build the derivative polynomial with
DensePolynomial::derivative and evaluate it; evaluate over
Dual[T].
Choice. Evaluate over Dual[T]. It returns and from one
pass, needs only Semiring (the formal derivative in luna-poly also needs
NatHomomorphism to form ), does not allocate a second polynomial
per derivative order, and composes with other dual computations through
eval_dual. The formal derivative remains the right tool when the
derivative polynomial itself is wanted; the test suite checks that the two
agree.
Reuse luna-poly evaluation
The bridge lifts the coefficients with Dual::constant, builds a
DensePolynomial[Dual[T]] or SparsePolynomial[Dual[T]] with the ordinary
constructors, and calls eval. It does not reimplement Horner’s rule, so
any change to luna-poly evaluation (and its normalization of zero
coefficients, which is why T : Eq is required) applies here too.
One variable for sparse polynomials
Problem. SparsePolynomial is multivariate, but a partial derivative
needs a choice of variable, and variable identity lives in the contexts of
luna-poly (VariableContext, ContextPolynomial).
Choice. The sparse bridge evaluates with the single assignment [x] and
is named sparse_univariate_*. A polynomial that uses another variable
makes eval abort. A multivariate API would have to take a variable
context and return a gradient; it is future work. Callers with a
contextual polynomial can partially evaluate the other variables first, as
the repository’s integration test does.
Compatibility names
The first release named the functions derivative_at,
value_and_derivative_at, eval_sparse_dual, sparse_derivative_at and
sparse_value_and_derivative_at. The dense_ and sparse_univariate_
names say which representation and which kind of derivative is meant; the
old names stay as plain aliases so existing code keeps working.
Correctness and invariants
Exactness in exact rings
For T with exact arithmetic (Int, BigInt, exact rationals) the results
are exactly and , by the identities above.
Rounding error of the dense evaluation
Use , , and the product lemma , .22 N. J. Higham, Accuracy and Stability of Numerical Algorithms, 2nd ed., SIAM, 2002, Lemma 3.1 and chapter 5.
Value. By the projection homomorphism is the plain Horner result. Each step multiplies the running sum by and adds once rounded, so carries factors for ; the leading coefficient carries , because the first step is exact:
Derivative (). The tangent step computes , and adding the constant adds an exact zero to the tangent. The derivative contains copies of , one for each step at which moves from the value chain into the tangent chain. Along such a path is rounded once when it enters, twice per value step , once when it moves into the tangent, and twice per tangent step : factors. Hence
the same bound as for evaluating the formal derivative by Horner’s rule. The relative error is small unless the terms cancel, that is unless is ill-conditioned at .
Cost
Dense: dual multiply-add steps, that is about multiplications
and additions of T, plus one array of lifted coefficients.
Sparse: per term one binary powering, dual products, plus one
dual product and one addition.
Alternatives rejected
- Symbolic derivative then evaluation. Two passes, an extra polynomial,
and a stronger bound on
T; kept asluna-poly’s ownDensePolynomial::derivativefor users who need the polynomial. - A private Horner loop. Faster by a constant, but it would duplicate
luna-polysemantics and drift from them. - Guessing a variable for multivariate sparse polynomials. Silent partial derivatives with respect to “the first variable” would be easy to misuse; the bridge aborts instead.
Boundaries
- Univariate only: no partial derivatives or gradients of multivariate
polynomials, no
ContextPolynomialsupport. - First derivatives at points only; no derivative polynomials (use
luna-poly), no higher derivatives. - No checked variants: dense and sparse evaluation do not fail except for the sparse abort described above.
- Dense and sparse
immutrepresentations only.